Archive for January, 2010

Selecting text within an element in CSS

An interesting discussion (which established itself as a branch from discussing behavioral characteristics of overflow) is currently taking place on www-style regarding a text selector control. Much of the detail is still being fleshed out, but I thought I’d give a quick overview.

Initially discussed as a possible way to remove suppress whitespace textnodes between inline-blocks, the control itself would take the form of a pseudo element incorporating function notation taking a matching pattern as an argument – something along the lines of ::text(matching-pattern) – which would have the ability to match strings of text within an element.

In contrast to my own confused ramblings (which I subsequently retracted), the consensus now is that the pseudo element should be excluded from crossing element boundaries in order to match a constituent of the argument, which means the full range of CSS layout properties can be exposed to the pseudo element (dependant on DOM-based pattern matching). Otherwise, consider Tab’s example:

p::text("foo b"){ display:block; }
<p>foo <span>bar</span> baz</p>

The above would split the pseudo element in two, since part of it would cross into the <span> in order to match the pattern given as the argument, resulting in:

<p><text match="foo b">foo </text><i><text match="foo b">b</text>ar</i> baz</p>

Not only would this be quite-rightly unintuitive from an author’s perspective, but it would also be harder to implement (compared to excluding element boundary crossing) from a vendor point of view. Having said that, the former issue could be solved by providing a limited range of CSS properties, similar to that of ::first-line, although conversation is veering away from such a resolution.

The sub-topic of discussion at the moment is how to avoid one ::text() boundary from crossing another.

If you can take some time out of your day, it’s certainly an interesting read.

Establishing a new method of float containment

So, in the many years in which floating (itself a workaround due to a lack of a more sanctioned layout tool) has become an integral part of CSS layouts, we have still not been provided with a control, whose primary purpose is float containment.

Authors have become reliant on either replicating a clearing markup element using generated content (borne from author findings), or have found that overflow:hidden|scroll|auto; applied to the parent, expands the parent’s margin-box to encapsulate the height of the child(ren). In fact, any property/value pair that can establish a new block formatting context (BFC) has the ability to do this. These pairs include:

  • float:left|right
  • position:absolute|fixed
  • display:inline-block|table-cell|table-caption
  • overflow:hidden|scroll|auto

Although there are a couple of areas in the spec that detail behavioral characteristics of BFCs, the crucial containment behavior can be derived from the Float specification

[...] an element in the normal flow that establishes a new block formatting context (such as an element with ‘overflow’ other than ‘visible’) must not overlap any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space.

9.5 Floats

A host of potential candidates

Whilst the aforementioned properties are all able to clear child floats, there is a major difference with one property/value pair in particular in the way that it computes an element’s width.

Every property/value pair that has the ability to establish a BFC – apart from overflow:hidden|scroll|auto – irrecoverably alters a block box’s computed width by applying the ’shrink-to-fit’ algorithm. In theory, we could try to emulate the expand-to-fit computed width of an in-flow block box with something like:

display:inline-block; /* Establish a new BFC, but that applies shrink-to-fit to computed width */
   width:100%;
   box-sizing:border-box;
}

Whilst this would be a plausible solution in the presence of any horizontal padding values, horizontal margins would remain an issue, which leaves overflow as being the only real solution.

Exploiting a property for it’s side-effect

Since we’re hacking a property purely for the purposes of harnessing a side-effect of it’s BFC-establishing characteristic, we have to contend with it’s primary purpose; controlling the clipping of an element’s content when it overflows that element’s content box.

In the common case where an element (which has a floated sibling) overflows it’s parent and the parent is established as the containing block, one of the overflow mechanisms will be invoked; this is a problem if you require the overflowing content of the containing block to remain visible. The only solution in this case is to ‘revert’ to one of the more traditional workarounds involving placing a clearing pseudo element after the parent’s document tree content. However, this author-invented solution acquires the pseudo element and means it can’t be used for more appropriate presentational purposes.

What’s needed

The crux of the matter is this – we’re being forced to use hacks in order to contain floats. Whilst float is an arguably adequate layout model for controlling content position amongst siblings (images, text, etc), it’s inadequate as a fundamental layout mechanism.

We’ve already identified that one particular characteristic of a BFC is that it contains floats in the manner that we require, each of the properties also have their own primary behavioral characteristics. So what I think’s needed is a new control which has the primary purpose of float containment in the same manner as a BFC currently does:

'float-contain'
Value:       auto | contain
Initial:     auto
Applies to:  non-replaced block-level elements
Inherited:   no

Granted, there are modules in the pipeline that will supersede float as a layout tool, but these are all still Working Drafts and likely to remain as drafts for a while longer (as far as I know). However, establishing a control that can be used as an interim solution whilst we still have to use floats, would be advantageous.

You can follow the discussion on www-style here (NOTE: the thread spans multiple months)