[CSSOM] Searching/Navigating stylesheets

I and other on my team been discussing ways in which the CSSOM could
be made more author-friendly, and have a number of ideas we'd like to
toss out for review.  Some we're rather attached to, other are
definitely half-baked but address an idea we think is important.  This
message is about navigating and searching stylesheets.

Right now, doing *anything* with actual stylesheets from the CSSOM is
a horrifying task.  A task that seems like it should be trivial, like
finding all the rules that apply to a particular element, requires
iterating through every stylesheet in the document and checking every
rule, comparing its selector against the element to see if it matches.
 I think there are some simple additions we can make to the API that
would make things like this easier.  All of these additions should be
useful for authors in at least some situations; they should also be
*extremely* useful for editors.


Searching a Style
Use Case: I want to directly manipulate the stylesheet value for the
specific rule that is applying some value to a particular element, so
that other elements which that rule applies to are also changed.

Problem: The only things I have easy access to are the @style rule on
the element.  To find the stylesheet rules that are applying to an
element, I have to walk all the stylesheets and manually test every
ruleset for whether its selector matches my element, then order them
(presumably by specificity) so I can easily decide which ruleset to
manipulate.

Possible Solution: Add elem.rules(), which returns a list of rulesets
(CSSStyleRule) that apply to the element, ordered by decreasing
specificity.  Also, elem.rules(‘property’), which filters the rulesets
to only include ones which actually set the particular property.

Note: This can be misused somewhat - if you just blindly alter the
first ruleset returned, assuming that it corresponds to a particular
selector, you’ll blow your foot off when, say, the code runs while the
user is hovering the element (and thus a :hover rule is now most
specific).  This particular use should instead be done by factoring
out the value you want to alter into a variable, and just altering the
variable instead.  We need to remember to note this explicitly when
speccing this.



Use Case: Similar to above, but I know that there is a *particular*
important ruleset that I want to mess with regularly, such as a “base”
ruleset for a particular class.

Problem: Similar to above, where you have to iterate the stylesheet.
Slightly easier, since you probably know what the selector is for that
particular ruleset you want, but that introduces a fragility where if
you change the precise selector used in the stylesheet your code stops
working (or worse, finds a *different* ruleset that also has that
selector).

Possible Solution: Add an @id name; rule that can be added to
declaration blocks, and a document.ruleByID(name) function which
returns the ruleset with the given id.



Use Case: Similar to above, but the alteration you want to perform is
to simply disable the rule temporarily.  (I'm not sure of the
usefulness of this to ordinary authors, but it's used in editors
constantly.)

Problem: Right now, you have to delete the rule and remember it
yourself, so you can restore it later.

Possible Solution: Add a rule.disable() and rule.enable() to CSSRule,
and rule.disable(‘property’) and rule.enable(‘property’) to
CSSStyleRule, which “turn off” the ruleset or the specific property,
and turn it back on again.  This could possibly be reflected by a
!disabled value appended to the property.



Use Case: I’m writing a javascript library that figures out what to do
based on the author providing custom CSS.  I'm writing a javascript
shim that looks for unimplemented CSS and provides a simulated
implementation.

Problem: Currently, doing this requires iterating through all the
stylesheets in the document, and for each stylesheet, iterating
through every ruleset to check if a particular property exists.  If
you're looking for a new/custom property, it's even worse - you have
to get the text of each stylesheet, *parse the whole thing yourself*,
and then find the rules you wanted.

Possible Solution: Allow declaration blocks to be selected with
Selectors.  A stylesheet is a root node, rulesets are children (some
types of rulesets, like media rules, can have more rulesets as
children), and properties are attributes on the ruleset.  You could
then easily find your custom property by doing something like:
var x = document
        .queryRules(“ruleset[my-custom-property]”)[0]
        .style.myCustomProperty;
Calling queryRules() on document would apply it across all active
stylesheets and aggregate the results.  Calling it on a particular
stylesheet would just query that particular stylesheet.

Note: Most browsers throw away unrecognized properties.  The partial
exception is current IE, which pretends the rule doesn't exist (it
doesn't show up if you enumerate .style nor does it affect
.style.length), but still records the property and make it available.
That is, with something like this:

div { color: red; foo: bar; }

...calling document.styleSheets[0].cssRules[0].style.foo returns "bar"
in IE.  This doesn't seem like a killer here, though - in the limit
case, browsers can reparse the stylesheet when an unknown property is
requested.  After all, the parser knows what the property's name was -
the error-handling implicitly looks for things that look like property
names and values so it can skip over them properly.  Assuming this
becomes popular, implementations can presumably do this a lot better,
like having some custom storage for unknown properties.


Thoughts?

~TJ

Received on Monday, 11 April 2011 19:58:14 UTC