RE: [css-gcpm] String-set issues

± Brad Kemper [mailto:brad.kemper@gmail.com]:
± 
± I've been giving some attention named strings in the latest GCPM draft [1]. I
± have some issues and comments. I'll start with the things I think are
± problems, and then I'll propose how I'd like to see it improve.
± 
± Problems:
± 
±  1.  'string-set' is a weird and confusing property name. It sounds like it is for a
± set of something, but I think really 'set' is meant to mean that you are
± assigning a (string) value to a name. We don't do that in other places where
± we have named things. For instance, we have '@counter-style', not
± '@counter-style-set'; '--foo', not 'foo-set', the 'font-family' descriptor of
± @font-face, not 'font-family-set', etc.
± 
±  2.  Pseudo-elements are excluded from being able to use 'string-set', so the
± 'content()' function has its own way of accessing them. That seems
± unnecessary. Just let pseudo-elements assign their contents to a named
± string, if you need that. It is simpler to learn, and less complicated, because
± you just use selectors like you normally do with pseudos. And really, most of
± the time, you won't even need that, because the actual element has access
± to the counter too, and that can be assigned to a name there. This would also
± eliminate the need for parentheses after the keyword 'content'.
± 
±  3.  'string-set' only gets the text of the element. I would think there are
± times when it would be useful to get all the content nodes, including links,
± bolds, small pictures, spans with class names, etc.
± 
±  4.  When 'string()' is used to access a named string, it ignores what was set
± on assigned to that name for elements not on the page. But in CSS3-content
± [2], the examples include 'META[author] { string-set: author attr(author); }',
± which selects something completely outside the page and uses it. Is this
± because the two drafts are out-of0synch, or are all these examples supposed
± to work somehow?
± 
±  5.  Normally when we assign a value to some sort of name in CSS, it is one
± value that is globally available. But with named stings in this draft, every
± name has multiple values (one for each selector-matched element within
± each page, multiplied by the number of pages, since the name only has page-
± wide scope in all the examples of this draft), so that the string() function can
± access right element, based on its position on the page. For instance, with
± 'string(theName, first)', the "value of the first assignment on the page is
± used". Meaning, I think, that if the element is the first occurrence of those
± on the page that match the selector, then it uses that element for the value
± assigned to that name. I think it would be better to just use selectors and
± pseudo-classes to select the right element, rather than to have that take
± place within the function inside the property value.
± 
±  6.  In the 'string()' function, the 'start' keyword is not well defined. It says "If
± the element is the first element on the page". Is that by document order?
± What if it has a parent? Technically, doesn't the parent come first? Also, I
± didn't really get what 'first-except' was for.
± 
±  7.  In the 'string-set', <content-list> can be used to construct a string from
± the text contents of the element (using 'content()'), as well as from literal
± text, counters, and attributes, and assign it to a name. But then, when you
± want to use a string like that, there is the 'string()' function. With that, you
± get that named string and construct a string from it and from literal text,
± counters, and attributes, and assign it to the 'content' attribute. This seems
± unnecessarily redundant, which can make it confusing. Since 'content' can
± already string together text from multiple sources, we don't really need to do
± it before assigning it to a name too, do we? If we need multiple things from
± the original element (its text and one of its attributes and its counter, for
± instance), they can just be each assigned to individual names, which can then
± be pulled into 'content' to be strung together. I think it is more author-
± friendly to just give us one place to concatenate strings together for the
± content, and let other properties and functions do their own things.
± Separation of concerns.
± 
± Regarding the first point above, I think in some ways, 'string-set' is similar to
± 'flow-into', especially if we axe the concatenation stuff of #7 above. They
± both use the similar 'content' or 'contents' keywords to create a variable-like
± name to hold the original contents of the element. I think we can play off
± that, using that as mental equity for changing the name and syntax of 'string-
± set'. So, instead of 'string-set', I propose the following:
± 
± Name:   copy-into
± Value:  none |  [ [ <custom-ident>  <content-level>] [,  <custom-ident>
± <content-level>]*  ]?
± Initial:        none
± Applies to:     All elements, but not ::first-line or ::first-letter.
± Inherited:      no
± The 'copy-into' property contains one or more pairs, each consisting of an
± custom identifier (the name of the named string) followed by a content-level
± keyword describing how to construct the value of the named string.
± 
± <ident> = The element or its contents, or its text, or the value of a specified
± attribute or counter is copied and placed into an non-rendered content
± fragment with the name '<ident>'. The values none, inherit, default, auto
± and initial are invalid content fragment names.
± 
± <content-level> expands to one of the following values:
± element|contents|text|attr(<identifier>)|<counters>
± 
± element
± the entire element is copied into the named content fragment (i'm using
± 'named content fragment' to mean the same thing as a named flow, but not
± intended to be flowed through multiple elements).
± 
± contents
± only the element’s contents are copied into the named content fragment.
± This is the default if <content-level> is not specified.
± 
± text
± only the element’s text (including normally collapsed white space) is copied
± into the named content fragment.
± 
± attr(<identifier>)
± the string value of the attribute <identifier> is copied into the named content
± fragment
± 
± <counters>
± the value of a counter() function, as described in [CSS21] is copied into the
± named content fragment.
± -----------------------------
± 
± So basically, it is the same as "flow-into", except that it does not remove
± anything, just a copy, and it has some other choices besides just "content"
± and "element" (I would also change "content" to "contents" in Regions).
± Plus, it can list several different names to copy stuff into, e.g. like this: 'copy-
± into: myContents contents, chapNum counter(chapter)'. And it has 'contents'
± as the default if one of the other levels is not specified instead.

For what it is worth, I warmly support this proposal.

The "string-set" property was always looking very strange and ineffective to me, only covering a very narrow set of use cases. For instance, it could not cope with ruby annotations, semantic formatting like <code> and other similar cases.



± By default, the content fragment name would be global, as the named flow is
± with 'flow-into'. But if one of the following pseudo-classes are used on the
± subject of the selector, then the name is locally scoped to just the page the
± element is on.
± 
± :nth-of-page(n)    The element is the nth matched element on the page.
± :first-of-page       Same as :nth-of-page(n), but where n = 1 (it is the first
± matched element on the page).
± :last-of-page       The element is the last matched element on the page.
± :start-of-page      The element is the first matched element on the page, and
± neither it nor its ancestors have any previous siblings that appear on the
± page.

This doesn't seem to be a possible solution to me. The effect of a property can't depend on the selector which applied it, as far as I know. Another solution will have to be found for this use case, I think.



± The content property would be able to accept the named content fragment
± as one of its value parts, just by using the identifier. It would not be part of a
± region chain, unless the whole element containing the named content
± fragment had "flow-into" something else.
± 
± So, for instance, here are Examples 1-3 of GCPM, re-written with this syntax:
± --------
± HTML:
± <h1>Loomings on the <b>Horizon</b></h1>
± 
± 
± CSS:
± h1::before { content: 'Chapter ' counter(chapterNumber); } 
± h1:first-of-page { copy-into: headerP1 counter(chapter), headerP2; } 
± h1::after { content: '.' copy-into: headerP3; } 
± @top-center { content: headerP1 ": " headerP2 headerP3; }
± 
± The value of the named string “headerP1” will be “Chapter 1", and the value
± of the named string “headerP2” will be "Loomings”. headerP2 will include the
± bold tags around "Horizon", because the <content-type> defaults to
± 'contents', not 'text'. The value of the named string “headerP3” will be ".”.
± The top-center content will be "Chapter 1: Loomings on the
± <b>Horizon</b>."
± 
± ---------
± HTML:
± <section title="Loomings">
± 
± CSS:
± section:first-of-page { copy-into: header attr(title) }
± 
± The value of the “header” string will be “Loomings”, assuming that section
± intersected with the page.
± 
± -----------
± CSS:
± 
± @page {
±   size: 15cm 10cm;
±   margin: 1.5cm;
± 
±   @top-left {
±      content: "first: " heading1;
±   }
±   @top-center {
±      content: "start: " heading2;
±   }
±   @top-right {
±      content: "last: " heading3;
±   }
± 
±   @bottom-center {
±      content: "start: " author;
±   }
± }
± 
± h2:first-of-page { copy-into: heading1 } 
± h2:start-of-page { copy-into: heading2 } 
± h2:last-of-page { copy-into: heading3 } 
± META[author] { copy-into: author attr(author); }
± 
± The rendered examples would be the same as in the spec, except that the
± author's name would appear at the bottom center of each page too.
± 
± 
± Brad Kemper

Received on Saturday, 22 November 2014 21:37:41 UTC