<Glazblog/>

CSS and style

Cascading Style Sheets and other exotic stylistic animals

Entries feed - Comments feed

Thursday 18 December 2014

Bulgaria Web Summit

I will be speaking at the Bulgaria Web Summit 2015 in Sofia, Bulgaria, 18th of april.

Wednesday 19 March 2014

A better CSS OM for parsed values

A large part of the current CSS Object Model sucks. More specifically, the CSSValue, CSSPrimitiveValue, CSSValueList, RGBColor, Rect and Counter interfaces are so poorly designed they're not implemented. I just tried to implement them for a project of mine and I must say the model is so weak and incoherent it cannot be implemented as is.

I have then tried to refine what's in the 2000-nov-13 spec of DOM Level 2 Style to reach something workable. I am NOT saying this has to be done or implemented. Call it a mental exercise I did just for fun, w/o caring about performance.

Let's first look at what's wrong:

Interface CSSValue

      interface CSSValue {
      
        // UnitTypes
        const unsigned short      CSS_INHERIT                    = 0;
        const unsigned short      CSS_PRIMITIVE_VALUE            = 1;
        const unsigned short      CSS_VALUE_LIST                 = 2;
        const unsigned short      CSS_CUSTOM                     = 3;
      
                 attribute DOMString        cssText;
                                              // raises(DOMException) on setting
      
        readonly attribute unsigned short   cssValueType;
      };

"inherit" is here considered as a special identifier despite of the fact a CSSPrimitiveValue can be a CSS_IDENT. There is no UnitType for "initial". A CSS_CUSTOM is, according to the spec, a "custom value"; but a custom value still has to be valid per CSS syntax so it should be representable with CSS_VALUE_LISTs and CSS_VALUEs.

Interface CSSValueList

interface CSSValueList : CSSValue {
  readonly attribute unsigned long    length;
  CSSValue           item(in unsigned long index);
};

All in all, this one is simple and should be quite ok. But one thing is missing: a property can accept a comma-separated list of whitespace-separated values. The current CSSValueList cannot express if the serialization of a CSSValueList should be whitespace- or comma-separated.

Interface CSSPrimitiveValue

interface CSSPrimitiveValue : CSSValue {

  // UnitTypes
  const unsigned short      CSS_UNKNOWN                    = 0;
  const unsigned short      CSS_NUMBER                     = 1;
  const unsigned short      CSS_PERCENTAGE                 = 2;
  const unsigned short      CSS_EMS                        = 3;
  const unsigned short      CSS_EXS                        = 4;
  const unsigned short      CSS_PX                         = 5;
  const unsigned short      CSS_CM                         = 6;
  const unsigned short      CSS_MM                         = 7;
  const unsigned short      CSS_IN                         = 8;
  const unsigned short      CSS_PT                         = 9;
  const unsigned short      CSS_PC                         = 10;
  const unsigned short      CSS_DEG                        = 11;
  const unsigned short      CSS_RAD                        = 12;
  const unsigned short      CSS_GRAD                       = 13;
  const unsigned short      CSS_MS                         = 14;
  const unsigned short      CSS_S                          = 15;
  const unsigned short      CSS_HZ                         = 16;
  const unsigned short      CSS_KHZ                        = 17;
  const unsigned short      CSS_DIMENSION                  = 18;
  const unsigned short      CSS_STRING                     = 19;
  const unsigned short      CSS_URI                        = 20;
  const unsigned short      CSS_IDENT                      = 21;
  const unsigned short      CSS_ATTR                       = 22;
  const unsigned short      CSS_COUNTER                    = 23;
  const unsigned short      CSS_RECT                       = 24;
  const unsigned short      CSS_RGBCOLOR                   = 25;

  readonly attribute unsigned short   primitiveType;
  void               setFloatValue(in unsigned short unitType, 
                                   in float floatValue)
                                        raises(DOMException);
  float              getFloatValue(in unsigned short unitType)
                                        raises(DOMException);
  void               setStringValue(in unsigned short stringType, 
                                    in DOMString stringValue)
                                        raises(DOMException);
  DOMString          getStringValue()
                                        raises(DOMException);
  Counter            getCounterValue()
                                        raises(DOMException);
  Rect               getRectValue()
                                        raises(DOMException);
  RGBColor           getRGBColorValue()
                                        raises(DOMException);
};

This is so completely crazy I don't know where to start...

  • CSS_UNKNOWN is supposed to represent a "value that is not a recognized CSS2 value". Then it should be thrown away by the parser as invalid and never reach the OM, right?
  • the list of units is long and not easily extensible
  • attr(), counter(), counters(), rect() and the more recent gradients or var() calls are all functions; adding a new setter and a new getter for each new type is overkill
  • attr() was extended by recent specs and can now take more than one argument. The above does not allow to individually modify those arguments.
  • "initial" and "inherit" are, as I already said above, covered by both CSSValue and CSS_IDENT here
  • let's suppose we have a CSSValue that is a CSSPrimitiveValue. Setting its cssText to "10px 10px" will then trigger an exception since a CSSPrimitiveValue cannot transmute magically into a CSSValueList...
  • I love how the spec prose says setStringValue() has "No Parameters"...

Interface Rect

interface Rect {
  readonly attribute CSSPrimitiveValue  top;
  readonly attribute CSSPrimitiveValue  right;
  readonly attribute CSSPrimitiveValue  bottom;
  readonly attribute CSSPrimitiveValue  left;
};

This looks and smells like a CSSValueList far too much.

Interface RGBColor

interface RGBColor {
  readonly attribute CSSPrimitiveValue  red;
  readonly attribute CSSPrimitiveValue  green;
  readonly attribute CSSPrimitiveValue  blue;
};

This cannot represent rgba(), hsl() and hsla() colors. We also have to use three CSSPrimitiveValue for the three color components because they can be a percentage or an integer...

Interface Counter

interface Counter {
  readonly attribute DOMString        identifier;
  readonly attribute DOMString        listStyle;
  readonly attribute DOMString        separator;
};

Again, something is missing here: nothing says if it's supposed to be a counter() or a counters() value. And no, the separator could not do the trick since it can be the empty string.

Requirements

To have a better OM for Values, i.e. an extensible OM that allows an application to deal with parsed values of all kinds, we need to change of perspective. First, the list of reserved idents, the list of units and the list of functions are not extensible. Secondly, we have cast issues between PrimitiveValues and ValueLists and we need a single interface. We can deal with all the issues with a single CSSValue interface:

New interface CSSValue

interface CSSValue {

  // ValueTypes
  const unsigned short      CSS_SYMBOL                     = 0;
  const unsigned short      CSS_NUMBER                     = 1;
  const unsigned short      CSS_UNIT                       = 2;
  const unsigned short      CSS_STRING                     = 3;
  const unsigned short      CSS_URI                        = 4;
  const unsigned short      CSS_IDENT                      = 5;
const unsigned short CSS_VALUE_LIST = 6; readonly attribute unsigned short type; attribute boolean commaSeparated;
readonly attribute unsigned long length;
CSSValue item(in unsigned long index);
raises(DOMException);

void setFloatValue(in float floatValue) raises(DOMException); float getFloatValue() raises(DOMException);
void setStringValue(in DOMString stringValue) raises(DOMException); DOMString getStringValue() raises(DOMException); };

Definition group ValueTypes

An integer indicating the type of the Value

CSS_SYMBOL
The value is a single character than cannot be interpreted otherwise. For instance the / character in the font shorthand property. The value can be obtained by the getStringValue() and set by the setStringValue() method.
CSS_NUMBER
The value is a simple number. The value can be obtained by using the getFloatValue() method and set through by setFloatValue() method.
CSS_UNIT
The value is a number followed by a unit. The number part of the value can be obtained by using the getFloatValue() method and set through by setFloatValue() method. The unit part of the value can be obtained by using the getUnit() method and set through by setUnit() method
CSS_STRING
The value is a string. The value can be obtained by the getStringValue() and set by the setStringValue() method.
CSS_URI
The value is a URI. The parameter of the url() function can be obtained by the getStringValue() and set by the setStringValue() method.
CSS_IDENT
The value is a CSS identifier. The value can be obtained by the getStringValue() and set by the setStringValue() method.
CSS_VALUE_LIST
The value is a list of values or a function. It is a function if the getStringValue() method does not reply the empty string. The list of values is whitespace-separated if the commaSeparated attribute is false and comma-separated otherwise.

Attributes

type of type unsigned short, readonly
The type of the value as defined by the constants specified above.
commaSeparated of type boolean
The separation type of the list of values. Meaningful only if the type attribute is CSS_VALUE_LIST. The list is whitespace-separated if the attribute is false and comma-separated otherwise.
length of type unsigned long, readonly
The number of CSSValue in the list. The range of valid values of the indices is 0 to length-1 inclusive.
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value is a not a CSS_VALUE_LIST.

Methods

getFloatValue
Retrieves the value of a CSS_NUMBER or the number part of the value of a CSS_UNIT. If this CSS value is not a CSS_NUMBER or a CSS_UNIT, a DOMException is raised.
Return Value
float The float value of this CSS_NUMBER or CSS_UNIT
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value isn't a CSS_NUMBER nor a CSS_UNIT.
getStringValue
For a CSS_SYMBOL, retrieves the single character used as a symbol.
For a CSS_STRING, retrieves the string. Enclosing quotes or double-quotes are NOT included.
For a CSS_UNIT, retrieves the unit of the value.
For a CSS_URI, retrieves the argument of the url(...) notation. Enclosing quotes or double-quotes are NOT includedt.
For a CSS_IDENT, retrieves the identifier.
For a CSS_VALUE_LIST and if that list of values is passed as the parameters of a function, retrieves the function name. Retrieves the empty string otherwise.
For a CSS_NUMBER and CSS_UNIT, a DOMException is raised.
No Parameters
Return Value
DOMString The float value of this CSS_NUMBER or CSS_UNIT
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value is a CSS_NUMBER or a CSS_UNIT.
item
For a CSS_VALUE_LIST, Used to retrieve a CSSValue by ordinal index. The order in this collection represents the order of thevalues in the CSS style property. If index is greater than or equal to the number of values in the list, this returnsnull.
For all other value types, a DOMException is raised.
Parameter
index of type unsigned long: index into the collection.
Return value
CSSValue The CSSValue at the index position in the CSSValueList, or null if that is not a valid index.
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value is a not a CSS_VALUE_LIST.
setFloatValue
Sets the value of a CSS_NUMBER or the number part of the value of a CSS_UNIT. If this CSS value is not a CSS_NUMBER or a CSS_UNIT, a DOMException is raised.
Parameter
floatValue of type float;
No Return Value
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value isn't a CSS_NUMBER nor a CSS_UNIT or if the attached property doesn't support the float value or the unit type.
NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
setStringValue
For a CSS_SYMBOL, sets the single character used as a symbol.
For a CSS_STRING, sets the string.
For a CSS_UNIT, sets the unit of the value.
For a CSS_URI, sets the argument of the url(...) notation.
For a CSS_IDENT, sets the identifier.
For a CSS_VALUE_LIST and if the parameter is not the empty string, make the list of values become a function and sets the function name. Make the list become a plain list of values if the parameter is the empty string.
For a CSS_NUMBER and CSS_UNIT, a DOMException is raised.
Parameter
stringValue of type DOMString
No Return Value
Exceptions
INVALID_ACCESS_ERR: Raised if the CSS value is a CSS_NUMBER or a CSS_UNIT, if the type of the value is CSS_SYMBOL and the string can be parsed as an other type of value, if the type of the value is CSS_UNIT and the string is not a valid CSS unit, if the type of the value is CSS_URI and the string is not a valid URI, if the type of the value is CSS_IDENT and the string is not a valid CSS identifier, if the type of the value is CSS_VALUE_LIST and the string is not a valid CSS identifier or the empty string.
NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.

Conclusion

The above should be enough to describe any CSS value, specified or computed. The model will become a bit complex for complex values but it ensures any web application can have access to parsed values, deal with their types and modify them. Let's take an example:

background-image: linear-gradient(to bottom, yellow 0%, blue 100%), url(foo.png);

This will result in the following OM (click on the image to enlarge it):

OM example

Again, I'm not saying the above is the thing to do or implement. It can certainly be improved, for instance for colors. A totally different perspective is also perfectly possible. I am only saying that making a better CSS OM allowing a full representation of parsed values in stylesheets and computed values is feasible. I hope the CSS OM will offer such power in the future.

UPDATE: the new CSSValue interface above lacks one thing, the ubiquitous cssText for parsing and serialization. Sorry for that.

Friday 31 January 2014

CSS Regions

If there is one and only article you should read about CSS Regions, that's this one. And the conclusion is quite clear and I agree with it:

CSS Regions give us the ability to do a lot of things that are otherwise not possible without them

Sunday 13 January 2013

CSS Paged Media and GCPM

I wrote a quite long article about the current CSS Paged Media and Generated Content for Paged Media specs/proposals and why they're outdated and are not enough. You can find it here,  on www-style.

Friday 17 August 2012

CSS Variables, why we drop the $foo notation

CSS Variables... A major request from the Web Authors' community since 1998...

Dave Hyatt and I shaped the first concrete public proposal in 2008 but the CSS Working Group could not reach an agreement about it. Variables, constants, mutable constants, OM or no OM, we had endless "religious" discussions about that and Hyatt finally removed his implementation from WebKit.

Then Tab Atkins made a breakthrough last february proposing a much better CSS integration, a model that fits nicely with what we already have. But then we had a problem with the $foo syntax everyone was asking for. Let me explain...

First, the proposed spec is NOT about variables and I seriously wonder if we should not change the title of the document. You may call the feature it introduces "variables" but at the deeper level, that's not about variables. That about Inherited User-Defined Properties. Don't take that as some political correctness or a blurb hiding the reality of the feature. The spec is really about letting you define your own properties and reaching their cascaded values. For instance:

div > p {
var-myprop: 1;
}

p {
var-myprop: 2;
}

In the above case, what will be the value of var(myprop) in a p contained into a div? Right, it will be 1 because the first rule has a higher specificity than the second one... Clearly, these beasts are not variables in the usual acceptance of the term.

Second, how are we going to use the values specified that way? We considered data(myprop), var(myprop) and $myprop. And despite of all the arguments expressed by the community in favor of the latter, the CSS WG decided during its recent San Diego face-to-face meeting to not follow the $foo path: $foo for the getter is too similar to a programming language, leading to confusion. The $ notation is used by preprocessors and script-based toolkits all over the place, it deeply conveys a notion of "programming language variable" or "preprocessor macro". And that's not what this spec is about since the feature introduced by the current spec shows important restrictions a variable or macro would not show:

  1. the value must be a set of valid CSS tokens; don't think of a preprocessor, don't dream of a partial string replacement. I repeat: a set of valid CSS tokens.
  2. you can't use the getter anywhere in CSS Stylesheets. You can use it only on the right-hand side of declarations (in other tems, after the colon in a '<property> : <values>' style declaration).
  3. we need an optional second argument to the getter giving a fallback value if the user-defined property is not set at all on the element.

Before shouting, don't misunderstand us: we clearly see the simplicity, readability and maintainability of the $foo syntax and we perfectly understand why the community prefers it. Being ourselves coders and implementors, we're used to manipulate $-based notations. But running that path implies too much confusion about our feature, will then lead to errors in live stylesheets, impacts existing CSS preprocessors that will have to change their own syntax to avoid collisions with ours, and will block us if we decide in the future to add real $-based macros to CSS. Again, we do understand why Web Authors prefer a compact and simple notation like $foo but we have decided it comes at a too expensive cost right now. We may reconsider this decision in the future (don't forget the spec is only a Working Draft at this time) but this will require solving all the issues detailed just above. Thanks.

Tuesday 19 June 2012

Media Queries and the 'view-mode' Media Feature are REC

Both Media Queries and the 'view-mode' Media Feature became officially a W3C Recommendation today. Yay !

Media Queries: http://www.w3.org/TR/2012/REC-css3-mediaqueries-20120619/

The 'view-mode' Meda Feature: http://www.w3.org/TR/2012/REC-view-mode-20120619/

Wednesday 6 June 2012

Transforms, Transitions and Animations

The CSS WG just resolved during its weekly conf call to allow browsers vendors to unprefix CSS 3 Transforms, Transitions and Animations immediately.

Wednesday 25 April 2012

The Open Web and CSS prefixes

Remember what I said a while ago here? I was not lying, here we are. :-(

Friday 3 February 2012

Wysiwyg is hard #5, CSS 3 Animations...

CSS 3 Animations are super powerful. I can't wait until they finally kill our JS-based animations. But they raise an issue that is well known by editor vendors: they're extremely difficult to manipulate in a wysiwyg environment, I already talked about it. As a matter of fact, none of the existing Animations editor on the market is able to edit a CSS 3 Animation wherever it comes from.

Here's the stylesheet I want us to look at today:

@keyframes bgchange {
  0%   { background-color: white; }
 100% { background-color: #b0b0b0; }
}

a { animation-name: bgchange; }

.dynamic { animation-duration: 1s }

What should a visual editor of Animations do with that ? It's totally impossible to infer from that stylesheet only that the dynamic class can apply in our document to anchors, so it's impossible to know the duration of the bgchange animation when it is applied.

An editor could present the bgchange keyframes rule, but only in a 0%-100% scale, not in a timeline since no duration is specified here. Even if you look for style rules specifying an animation-name, you won't be able to find an animation-duration...

In fact, we have this problem because we are mixing in CSS 3 Animations two notions: the animation itself and assigning an animation to an element. Authors of CSS 3 Animations chose to decorrelate the animation from time, and we have only percentages in the @keyframes rule. But that means such a rule cannot be presented as a timeline. They also chose to implement the assignment in a way the keyframes assignment and timing assignments can be independent; so they can't be presented as a timeline either...

Since Animations are a major feature of CSS 3 that will inevitably trigger more standalone and web-based apps to edit them, I think we have a rather serious design issue here. Some solutions are possible, they all have upsides and downsides:

  1. change the default value of animation-duration; it's currently 0 and it could become for instance 1s. In that case, presenting a timeline is always possible. Harm to existing web pages is low, most of the animations are set specifying name and duration in the same style rule and are usually triggered by a class or attribute.
  2. stop having individual properties for animation name, duration, delay and timing-function. One property only setting the four. That way, one the CSS rules in our example above must become .dynamic { animation: bgchange 1s; } and we don't have editability problems any more. That change will require roughly two thirds of existing web pages to update their code since they often set the individual properties.
  3. modify the @keyframes syntax to include mandatory default timeline metadata for that keyframes set. For instance something like:
    @keyframes bgchange 1s 3s ease-out {
     0%   { background-color: white; }
     100% { background-color: #b0b0b0; }
    }

    Since the animation shorthand property still sets animation-duration to 0, and since as said earlier most of the animations are set specifying name and duration in the same style rule, the effect on existing web pages will probably be minimal. If the web author does not use the shorthand but individual properties, unspecified properties (except animation-name of course) get their default value from the @keyframes rule. We also need to extend CSSKeyframesRule to be able to reach these default timeline values through the Object Model. I even suggest extending CSSKeyframeRule to be able to get the time corresponding to the percentage of that frame for the default timeline metadata of the current keyframes set. I must say this solution has my preference.

This list is not exhaustive at all and I'm all ears if you have something else on your mind. But we do have an editability problem here and that's one I would really like to see resolved, for once in CSS, or we will have only standalone and web-based editors able to edit only a very restricted set of Animations, and not all of them.

Please try to post your comments into www-style and not here. I started a thread here about this article and the problem it raises.

Monday 28 November 2011

One pseudo-class, one document, two layouts

It's possible at super-minimal cost to have for the same document liquid AND fixed-width layout, thanks to ZE POWA of CSS...

In a fixed-width document named index.html, you usually have a rule setting the width or max-width of the main element. Something like

#main750 {
  max-width: 750px;
}

Right? Now think :target pseudo-class and tweak your style rule as followed:

#main750:target {
  max-width: 750px;
}

Do you understand the trick?

Yeah, your document now has liquid layout if called by URL index.html and fixed-width layout if called by index.html#main750 :-) TADA !

Wednesday 23 November 2011

Some thoughts about editing CSS 3 Animations

I started working on an editing tool for CSS 3 Animations inside BlueGriffon. And I discovered that editing Animations is hard. Just like the rest of CSS, eh :-) Animations are powerful but hard to edit in the general case.

Case 1

We have a html document with one @keyframes myAnim1 { ... } rule. When the user clicks on a given element, another element acquires through JavaScript an animation-name, an animation-duration and an animation-delay. In other terms, an editing environment opening that html document cannot determine from the document instance the animation myAnim1 can be attached to the element, when it should start and how long it will last.

Case 2

The document contains the @keyframes myAnim1 { ... } rule but myAnim1 is used through animation-name by two selectors targeting two different elements in the stylesheet. The corresponding animation-duration and animation-delay differ. Then the keyframes' set myAnim1 must be represented twice on a timeline, and the key here is clearly the selector.

Case 3

The Web developer is a JavaScript zealot and all animations are launched and chained through JavaScript instead of using a single class on a single element,  descendant combinators and animation-delay. Then it's impossible to present a  timeline of all animations showing when they will start and end, proposing a global vision of the animations' set of the document.

Conclusion

Because of the above, a single timeline for all animations living inside a document is impossible in the most general case. I mean, if you take an arbitrary Web document retrieved from an arbitrary Web site using Animations, it's very unlikely that you'll be able to edit these animations using an editor showing a single-timeline view.

Sencha Animator shows a single timeline and that's why it is unable to deal with an arbitrary Web page. Adobe Edge is a worse case since it deals with Animations only through a huge JavaScript library... Launch Edge, make an animation, export the document, look at the CSS : it's empty.

So my editor will have two views, one for the keyframes' sets, one for the selectors and the animation properties. It's a little more complicated (although I'm not really sure about that) but it will allow you to edit all your CSS 3 Animations. Unless you used Edge and its ugly JS-based design, of course ;-)

Animations Editor sketch
Click to enlarge

Wednesday 16 November 2011

CSS vendor prefixes, an answer to Henri Sivonen

Disclaimer: I'm one of the two co-chairmen of the CSS Working Group and the opinions below reflect exactly what I think of the CSS process not only as an individual contributor but also with my co-chair hat on.

The ineffable Henri Sivonen has contributed a long, a very long, a probably too long post about CSS Vendor Prefixes. In short, he thinks they are harmful and should be dropped. I tend to totally disagree and will explain why below. In bold, Henri's words. Indented and normal, my responses.

vendor prefixes are hurting the Web
No. Said like that without justification and as a first sentence in Henri's prose, no. They are not. Vendor prefixes allow vendors to implement experimental CSS features without harming the namespace of unprefixed properties.

They are hurting Web authors
Here, I agree. As they are now, vendor prefixes are hurting Web authors because a) the browser market does not evolve that fast, in particular on mobile devices b) some browser vendors never get rid of prefixed properties. As a result, Web authors have to maintain several prefixes properties per feature.

They are hurting competition in the Web browser space
I totally fail understand why, maybe the rest of Henri's article will explain why.

It would also make sense for browsers to implement other browsers’ prefixed features to the extent existing content uses prefixed features
This is non-sense. There are only two cases : first case, the prefixed property was proposed for standardization and then all browser vendors will probably implement it ; second case, it was not proposed, probably because it's too proprietary or badly spec'd, and no other browser vendor will implement it because it lacks a good definition or use case.

Why do we have vendor prefixes?
Henri says the discussion is Member-confidential. It is only because that discussion is super old, long before the CSS WG decided to go public. There is nothing secret here : we have vendor prefixes because vendors needed a way to start implementing new features w/o saying their implementation was the official final CSS property.

there is no clear rule for using vendor prefixes in the DOM
That's correct and that is hurting the Web. Mozilla does it right: when it implements a new API these days, everything is prefixed with moz. That way, if the final standardized API differs from the experimental implementation, it's easy to get rid of the moz-prefixed version, tell authors hey guys this was experimenal anyway, and finally switch to the stable standardized version.

Vendor Prefixes are “Hell” for Web Authors and Authoring Tool Vendors
That is 100% true, as I detailed above for Web authors. For Authoring tool vendors, it's a nightmare. But let me tell you one thing: the "HTML live standard" of the WHAT-WG is a nightmare of a MUCH greater magnitude than this one. In comparison with the fact what the whole world has now to call "HTML" can change overnight, CSS vendor prefixes are a sweet, predictable, simple candy.

Web authors have to say the same thing in a different way to each browser
Only because browser vendors are shipping "experimental features" in non-experimental versions! Experimental features should be available only in "technology previews" of the browsers, not in stable versions. That way, everyone could still test the experimental features according to the W3C rules BUT Web authors would not use prefixed versions in production. Since almost all browser vendors switched to a fast release process, I don't see the problem here. A feature would move from prefixed to unprefixed as soon as the spec reaches stability, ie CR status.

pure hell
I have the feeling Henri is using my opinion here to tell the world a "Live CSS Standard" would be better. I have the gut feeling he's advocating for a WHATWG way of doing in the CSS Working Group. I think this is totally wrong. I think this would make CSS collapse and trigger the hatred of CSS Authors because they will be totally unable to say what is CSS at a given point.

When the possibility of using engine-specific prefixes exists, engine-specific Web content follows.
This is just false. CSS stylesheets are full of CSS hacks because the different browsers don't evolve at the same speed, because they don't all offer the same feature set at the same time. Even if prefixes are removed, that will persist and therefore engine-specific Web content will persist.

Thus, a Web author who does not want to poison the standard namespace will only use the prefixed CSS keywords or DOM APIs
NO. Henri just doesn't understand Web authoring here. The only way to stop harming a stylesheet with different prefixes for the same property is to stop using prefixed properties. EXPERIMENTAL features are experimental, and Web authors are using them because browser vendors are shipping these features as if they could be used in production. They cannot. They're subject to change or even disappear at any time.

If a site uses CSS with the -webkit- prefix, users of Firefox, Opera or IE get a worse experience even if they implemented the same feature with their own prefix or without a prefix
It's only because browser vendors are dumb. And I do mean it. The rule should be this one: if the CSS parser encounters a prefixed property for another browser, honour that property as if it were prefixed for us UNLESS an unprefixed or prefixed for us valid declaration for that property was already set. That would drastically reduce the problems on the Web. Of course, if -webkit-foo and -moz-foo are not based on the same version of the spec - and that happens all the time - that will be helpless.

Back in the old days when Internet Explorer introduced a feature that they just made up, they did not make their mark on it by baking their name into the identifier
Totally false for CSS. Microsoft Word is full of totally proprietary -ms-* properties since the first version of Word based on XML and CSS, in the "old days".

Last week, insertAdjacentHTML finally shipped to the Firefox release channel.
Unprefixed, yes. But that's normal, we have here a de facto standard, IE and its online doc, where we usually have a de jure standard, a W3C specification. That IE feature is more than ten years old and the IE-specific Web is full of it. It is totally out of question to do something even lightly different from what IE does. So prefixes are not needed. We already have the standard!

The situation is harmful for Firefox for mobile, Opera Mobile and IE on Windows Phone.
That's possible and I don't care. What I see is that your proposal to get rid of prefixes will be even more harmful to non-browsing tool vendors, Web authors who will never know if a feature is experimental (and then subject to changes) or not, and finally Web users.

In a word: No.
No only because at the time a standard is published, the Web is already full of prefixed properties. And the Web is full of prefixed properties because browser vendors ship experimental features to all final users, allowing Web Authors to use these experimental features in production Web sites. Even telling them "go ahead, it's tagged experimental but it's shipped to everyone anyway".

Lea Verou's prefix free...
...is in my opinion dangerous. It tells Web authors that a prefixed version of a property equals another prefixed version of the same property. And that is just false. Lea's prefix-free tool is FAR from enough. Trust me on that please, I had to implement a few thousand lines to start working around the problem and I only have a partial solution... This is MUCH MORE complex than what Lea's tool lets Web Authors think it is.

In practice, vendor prefixes don’t prevent legacy from accumulating ahead of CR. It’s not useful to pretend that they do.
Again, only because of browser vendors themselves. They wanted CSS prefixes but don't use them according to their original wishes. Experimental is experimental, ie "should not be used in production". Since whatever you ship will ALWAYS be used and abused, shipping experimental features to the masses could only lead to legacy prefixes accumulating in the wild. This is browser vendors' fault.

If -webkit-CSS meets the client requirement within budget today, -webkit-CSS is used.
Exactly what I said above. So don't make -webkit-CSS available to the masses. Make it available in tech previews, beta channels, etc. But not stable versions.

browser vendors should stop adding more prefixed CSS features and DOM APIs
Basically, it says CSS should become a Live Standard. I totally disagree and will do all I can to avoid that.

For CSS, features like this include at least Transitions, Animations, 2D Transforms and 3D Transforms
That opinion would be hilarious if it was not tragic... These features are almost similarly implemented but there are still stuff discussed in the spec itself. The standardization is NOT done yet, and the features are complex enough a new painful hole could emerge in the coming weeks.

I also think that it would make sense to unprefix single-vendor features
Ah, that I could agree with IF there is some sort of formal environment here : a) the vendor must consider its implementation is frozen b) it was shipped for the first time more than a year ago, so this implementation is now a de facto standard because Web sites are using it.

In these cases (flexbox, gradients), I think it would make sense to stop changing the spec, to unprefix the features in browsers that are closest to the current drafts and then prioritize work to match the spec in other browsers
Clearly no. That's what the WHATWG does, only implementations matter and specs don't, as Hixie told me during TPAC. I don't want to see that happen in CSS, ever. Furthermore, it would trigger an absolute nightmare for Web Authors and Web Authoring Tool vendors.

I think when browser vendors implement a feature experimentally, the feature should stay in experimental builds (nightly builds, “labs” builds or similar) until it is close enough to a “final” design that it can be taken as a constraint for future changes to the feature.
AAAAAH FINALLY. Here we agree entirely. Just what I said above.

I think the system where a WG can change anything until Candidate Recommendation (...) is fundamentally broken. I think decisions whether a feature can be changed should be depend on deployment.
I totally disagree. It's broken because browser vendors break it shipping experimental features in non-experimental versions. Basing prefix removal strictly on deployment is the most harmful decision to Web Authors and Web Authoring Tools that you could take. Only stability matters, not deployment.

Update: now it's clearer. One of Henri's goal is to make CSS adopt the Living Standards way of doing things. My opinion is that it would kill CSS or at least be incredibly harmful to it. So I will fight that. And to reply to Rik in that IRC log, no, I don't always mention my co-chair role when I discuss CSS. I even mention "hat on" or "hat off" when I do.

Saturday 5 November 2011

CSS vendor prefixes, again...

We still have a major problem in CSS wrt CSS vendor prefixes... We have -moz-*, -webkit-*, -ms-*, -o-* and more all over the place and we all agree that what we have is suboptimal. During W3C Plenary Meeting this week, we discussed CSS Gradients. Introduced by Apple with a -webkit-* prefix, we now have at least 3 incompatible versions of gradients spreading in Web pages. Being myself an HTML+CSS editor implementor, I can tell you this is pure hell for me. But beyond editing issues, it's also a strong issue for Web authors because they have to maintain multiple versions of the same property in their stylesheets to be compatible with browsers that are not cutting-edge. Let's face it: we have a problem with Gradients (a really great feature by the way) because a browser vendor shipped it to the masses and there is no way to prevent web authors for massively adopt immediately such a great feature. It happened in the past for Gradients, it will happen again for other features.

On another hand, browser vendors need a way to implement experimental features and ship them, even if it's only for testing purposes. The CSS WG decided a while ago that if a given feature is stable enough across browsers, it should move faster along the REC track and the CSS WG should issue a call for implementations, tested with an official test suite.

But that's probably not enough. We still have one issue here: the "extraction" of a given feature from a given spec is not always easy, requires editing work and it's not instantaneous with respect to W3C Process. And if we keep the feature in its original spec, it means we call for implementations before the spec reaches a global interoperability, and that's not what the W3C Process wants. Thinking out loud, I wonder if a better solution isn't the following one:

  • new strictly-experimental prefixed properties and values can be shipped but they are disabled by default in content. It means that they will output a warning on the console at parse time and they will not be stored in the CSS OM, not honored in Layout. I understand this could slow down a little bit CSS parsers but nothing comes for free.
  • these experimental features can be enabled by the user using a special "Debug" menu.
  • a web page can programatically prompt the user to enable these features, through a new API probably on document. App-level (what we call chrome CSS in XUL) CSS does not need that, experimental features are still enabled by default in app-level CSS. I think enabling should be domain-wide, not global.
  • all experimental features are disabled again for all domains when the browser is updated.

Then browser vendors can still implement, ship, make the community test the implementation, allow Web authors use the features in experimental web sites.

Opinions? (again, I'm only thinking out loud here to start the discussion)

Friday 30 September 2011

Selectors 3 and CSS Namespaces Module are RECs

At the end of 1998, a while after the release of CSS 2, I took an action item in the CSS Working Group to become the author/editor of a new beast in our Group, a module... CSS 2 was already a big big change from CSS 1. And when I say 'big', it means the spec switched from the 15 printed pages of CSS 1 to the hundreds of CSS2. So we decided to 'modularize' CSS 3. Since I already worked a lot on Selectors and even implemented them before, this was a natural choice for me.

At the beginning of january 1999, my first draft was ready. It's unfortunately not public and the original document was lost when I left my employer a year later (Electricité de France, fwiw). The second draft though is still available, although in a web space restricted to CSS WG Members, sorry for that... The first public draft, dated 03-aug-1999 is available here. You can see that in that document, the :subject pseudo-class, corresponding to the $ descriptor present in the current Selectors 4 draft, was present... Alas, it was later removed because of browser vendors expressing implementation concerns. That pseudo, a top request from the Web Authors' community, originally came from something I specified and implemented myself in my transformation language based on the CSS syntax/grammar: STTS3.

Despite of what I could call a poor support from implementors at that time, I also decided to add major new stuff to Selectors:

  • the :nth-child() and friends pseudos, captured from an early draft of XSL/XPath I found impressive. I really wanted them to be able to style table rows, columns and cells. For the record, the an+b syntax of the argument was proposed by Tantek Çelik's father.
  • the :target pseudo, proposed by Håkon Lie. Håkon did not suspect the power of that pseudo at that time, until I found a super-interesting use case for that pseudo... See the demo (in a browser implementing :target, of course...).
  • the indirect adjacent combinator ~, that was really missing.

Then namespaces and the negation pseudo :not() arrived, and the spec changed only a little bit between 2000 and now, waiting for browser implementations, a completed Test Suite and interoperability.

Today, after more than 12 years, I am happy. Really happy and a bit proud too I must say. Older, but happy :-) My baby just became a W3C Recommendation, after the hard work of many people who caught the flag and became editors of the document and/or the Test Suite... Yay!

Similarly, the original CSS Namespaces proposal, authored by my co-chair Peter Linss during the Netscape era (gosh, time flies...) became a REC yesterday after too many years of wait. Yay again !

All in all, the CSS Working Group released 5 new W3C Recommendations between the beginning of june 2011 and now ! Wooohooo !

So where are we now? Selectors 4 start emerging, and I would like to issue here a clear and loud warning with my CSS WG Co-chair hat on: this is an early stage draft and the presence of a feature in that document does not imply IN ANY WAY that the final specification will contain it and that browser vendors will offer support for it. In particular, I already noticed the major response of the community to the presence of the subject selector and the matches-any functional pseudo-class. Guys, please cool down... These two features still represent a real implementation challenge for browsers and I just cannot tell if they will remain in the spec or disappear from it. Please note, this is not the first time - as I wrote above - such features are included into a Selectors draft... Been there, done that.

Don't misunderstand me ! I am not saying these features will never ever reach a browser near you ! I am only saying standardization is a complex process also based on implementability of the features we design AND browser vendors' strategies. Be optimistic, but also be realistic. Thanks.

Tuesday 7 June 2011

CSS 2.1, CSS 3 Color and MathML for CSS Profile are RECs !!!

YAY !!!!

Tuesday 24 May 2011

CSS OM, issue #2

In the CSS Object Model, interfaces CSSStyleDeclaration, CSSRule and CSSValue have access to the attribute cssText. So basically, you can serialize a stylesheet using that. All of a stylesheet? Unfortunately not...

  1. first, nothing is said in the DOM about the character set used to serialize your stylesheet in cssText. Even if your stylesheet uses a @charset rule, it's likely your serialization through cssText will be utf-8 utf-16...
  2. then @namespace rules are not available through the DOM at this time. I should add there is no CSS OM extension for them in the CSS 3 Namespaces module because there was no consensus about that and it was left for the forthcoming CSS OM spec.
  3. because of the previous item, it's just impossible at this time to serialize a stylesheet using namespace prefixes unless your rendering engine has proprietary extensions to deal with @namespace rules. There are two options here: a new type for CSSRule and then a simple loop over all rules in the stylesheet is enough to serialize it (modulo the charset issue mentioned above), or a table of prefixes/URIs attached to the stylesheet itself and then you need two loops; one for @charset and @import rules, the serialization of @namespace rules and finally the second part of the loop over remaining stylesheet rules.
  4. cssText is not available on CSSStyleSheet. On that interface, cssText could do all we need above: deal with namespaces, convert to the correct charset, and whatever we need in the future.

Thursday 19 May 2011

CSS OM, issue #1

I am starting with this blog entry a list of CSS Object Model issues I am hitting working on my editor, BlueGriffon. Here's the first issue below, more to come later:

Interface CSSStyleSheet does not deal with rules but only with rule indexes. Just like CSSMediaRule. That has an immediate side effect for content editors willing to edit stylesheets: moving a single rule in the list of rules attached to a parent stylesheet or parent media rule will not preserve the reference to your rule! Given a valid index in a stylesheet sheet, the following code moving the rule down into the list of rules will return false:

var rule = sheet.cssRules.item(index);
var newIndex = sheet.insertRule(rule.cssText, index + 1);
var newRule = sheet.cssRules.item(newIndex);
sheet.deleteRule(index);
alert(rule == newRule);

This is clearly suboptimal. CSSStyleSheet and CSSMediaRule should be able to deal directly with rules. I suggest adding the following to Anne van Kesteren's improvements to the CSS OM:

readonly CSSRule insertCSSRule(CSSRule rule, unsigned long index);
void deleteCSSRule(CSSRule rule);

That way, the code above could become:

var rule = sheet.cssRules.item(index);
sheet.insertCSSRule(rule, index + 1);

And that's all. insertCSSRule() would detect rule is already present in the list of rules of sheet and simply move the rule to its new position.

Wednesday 18 May 2011

Wysiwig is hard #4, editing StyleSheets...

Editing stylesheets in a wysiwyg editor can be hard. For multiple reasons:

  1. stylesheets are of three different kinds: embedded into the document through a <style> element, linked through a <link> element, or imported from another stylesheet (and nesting is possible) through an @import rule. In html5, the possibility to have embedded styles anywhere in the document adds another layer of complexity, in particular in the case of presence of the scoped attribute... I must admit BlueGriffon is not ready for that yet, I have not resolved all the technical issues related to scoping. In particular, the specificity of scoped styles is unchanged and I am not sure this is coherent with the spirit of the CSS Cascade. This may have deep implications on the wysiwyg editing side but an ID selector's specificity should probably be added to all scoped styles.

    Listing all stylesheets applied to a given document is simple using one single CSS OM call. Determining if a stylesheet is embedded, linked or imported is done through the parentStyleSheet and ownerNode attributes on CSSRule and StyleSheet interfaces.

    Serialization of a stylesheet is painful. I had to write thousands (yes, really) of lines of JS to handle that because unknown CSS rules are not preserved by the browsers' style engines. Even if they were, an editor just cannot consider a vendor-prefixed property has to be output unchanged. A style change by the user could affect vendor-prefixed styles stored as unknown rules in the CSS OM...

  2. adding a given style to a given element is hard; not only you must find all the style rules that apply to the element for the property you want to edit, but you also need the specificities of those rules. When you have the list of couples (rule, specificity of the rule), you must find the rule of highest specificity. If that rule is editable, i.e. if the stylesheet can be modified by the application, then you must create a style rule or a style attribute of a high enough specificity and/or importance overriding the current style. If the stylesheet is not editable (file not writable, remote resource), then you may have to create a new embedded or linked stylesheet (or use a style attribute) to apply the style you want. I don't even want to think about the scoped styles case for the time being, it's a nightmare.

  3. html5 defines a new presentational attribute on all elements: the hidden attribute... It is not entirely clear to me if a true value of that boolean attribute should map to the CSS display: none; style or use another mechanism to hide the element. In the case of the former choice, this will add another layer of complexity to the editing algo for the display property. Furthermore, in the case what's the position of the hidden attribute in the CSS cascade? I think the html5 author's spirit make it override all other styles. But that's not how the Cascade works, giving a very low specificity to presentational attributes. Should the hidden and the style attributes have the same specificities? Should hidden exist at all? I don't think it should. It's presentational and we have the display property anyway. The only reason why it should exist could be an accessibility reason, voice browsers often using the DOM and not the CSS OM. By the way, the spec says "When specified on an element, it indicates that the element is not yet, or is no longer, relevant". Does it imply that styles contained in a <style hidden> should not apply any more? In other terms, does it disable the stylesheet? This hidden attribute is a can of worms, underspecified, and it will raise tons of technical issues in the near future.

  4. editing an embedded stylesheet is a pain. I'm sure you thought this should be the easiest case. No external file or remote resource, everything is inside text nodes. Simple, eh? It's not. It's not if you want the dialog editing such a stylesheet to be non-modal... Let me explain: if the dialog is not modal, then all changes to the styles are immediately applied. Let's suppose my embedded stylesheet contains only p { color: red; } and that I want to change that color to blue. I have two choices depending on the frameworks I am using:
    1. first case, I have access to an abstraction layer allowing me to tweak directly the source of the stylesheet; then I can change the red into a blue, and replace the textual contents of the style element by the new stylesheet
    2. I have only access to the CSS OM; then I can change the property value in the CSS OM, serialize the stylesheet and then replace the textual contents of the style element
  5. But in both cases above, I have a serious problem: the stylesheet I was editing does not exist any more! The style rule I was editing does not exist any more! They were replaced by a new stylesheet and a new style rule after parsing of the new textual contents... So if I kept a reference to the stylesheet and style rule I edited, they suddenly get a null ownerNode, my whole UI still shows style objects that are now only references to objects unrelated any more to the document. That implies that every style change, I repeat every style change, in an embedded stylesheet from a non-modal UI should totally reflow the UI or at least, reassociate all UI to new style objects that did not exist before... Urgh, to say the least.

Editing styles in a wysiwyg editor is not, as I heard it during a chat a few months ago, "only a matter of a few calls to the CSS OM". It's painful, expensive both in terms of performance and footprint, sometimes tricky in terms of UX and requires stuff that the CSS OM does not implement . It can be really hard.

Wednesday 30 March 2011

CSS 2.1 !!!

plinss: I propose advancing 2.1 to PR
plinss: Any objections?
RESOLVED: Advance CSS2.1 to PR. 

Tuesday 29 March 2011

border-radius rant...

Sorry to be less technical than in general but something painful just happened to me while working on the CSS editor of BlueGriffon and I wanted to share that with the CSS community...

BlueGriffon is based on the source of Firefox 4. The border-radius property is then implemented unprefixed in the rendering engine. Even if BlueGriffon outputs styles for other rendering engines (using Peter Beverloo's excellent list and my JSCSSP parser/serializer), I considered that one version (the last public one) of each rendering engine is enough.

And I just got a mail from a user complaining that -moz-border-radius is missing...

From a user's perspective (hear web author's perspective), this is a perfectly fine request. From my software implementor's point of view, it's a nightmare.

If CSS vendor prefixes are useful for standardization and implementation of experimental features, they're harmful to the users' community and painful to software management. Our current situation wrt vendor prefixes is still suboptimal, to say the least.

I am not going to support in BlueGriffon prefixed versions of properties that are now unprefixed in the last public version of browsers. Example: I don't plan to support the WebKit gradients forever...

- page 1 of 5