We've just been working on initial-letters and have some feedback. As far as I'm aware it's only webkit (with a prefix) offering a partial implementation on this (is this true?). So I realise this specification is in its early days. Here's what we've come up with:
1. Allow shape-marginFor initial-letters-wrap: all
, there's a definite need for the shape-margin
property, which should apply either to the shape manually specified with shape-outside
or to shapes derived from the glyph outlines. Relying on the end-inline margin is not not flexible enough, say for letters like "Γ" (greek capital Gamma) where you want to push text away from the protruding horizontal stroke, or "C", where without a margin the text could disappear into the mouth of the "C"
Inline initial-letters are auto-sized around the visible bounds of the content; around the size of the glyphs. What's not clear if whether this sizing algorithm should affect the linebox or not:
left-most: our rendering, where we auto-size the initial-letters elements as specified, but we don't push the linebox up to accomodate it.
middle: webkit's rendering, where the box extends down as far as required, but never goes above the cap-height of the letter.
right: a third option - the element is sized to fit the content, and the linebox is pushed up to include it.
You could make coherent arguments for the left or right renderings fairly easily; probably the left is more useful, as otherwise the height of the first line (and therefore its apparent position relative to the top of the block) will depend on its initial letter, which is likely to annoy someone at some point. I'm not sure Webkits approach will work for non-latin scripts; it's not testable as Webkit doesn't seem to support anything other than alphabetic alignment. Which brings me neatly to my next point.
3. Alignment and font-sizingAlignment and sizing are two sides of the same issue for initial-letters. The specification goes to some length to describe how the letters have two alignment points - a two-line drop letter "A" would have its top top alignment at the cap-height of line one, and its bottom alignment at the baseline of line two, as shown with this example from the spec:
But this description only makes sense for fully dropped letters, i.e. where sink==size
, and it necessarily fails if the lines aren't all the same size as the block element's line-height
, as demonstrated in https://drafts.csswg.org/css-inline/#initial-letter-block-position.
So while this description is helpful to understand the intention of the specification, I think it should be clear it's no more than that. When you come to implement it, you're positioning the text on the first line without any knowledge of what's to come. Layout necessarily goes like this:
initial-letters
.For alphabetic text this is effectively what the spec says already. But when aligning on a hanging baseline (for example), the outsize letter will effectively drop without any further shift.
The Hindi initial-letter was aligned on the hanging baseline of the first line. That's all. No further shift was required. In fact with dominant-baseline: hanging
on the paragraph and alignment-baseline: baseline
on the first-letter, there's no need for the initial-letters-align
property to exist at all.
I would suggest dropping it completely and simply using alignment-baseline
exactly as it is defined for regular inline elements, although perhaps disallowing top
, center
and bottom
as values.
"But what about atomic inlines", you may ask?
4. Atomic inlinesAtomic inlines such as images can be used as an initial letter as the spec is now, and the intention appears to be that they're aligned based on the same alignment points derived from the initial-letters
property. But the spec is silent on the mechanism for this. I presume the height is to be set then the width scaled to match? For example, if using an image:
<p>
<img style="initial-letters: 3" src="fancy-I.png"/>nitial letters can be images too
</p>
then the image will need to be scaled to cover three lines, and its top aligned with the top of the first linebox. Again there's no need for initial-letters-align
: the "border-box" value of this property looks like it is intended to set the position and size of the image to be identical to the layout results you'd expect from this:
<p>
<img style="alignment-baseline:top; height:3lh" src="fancy-I.png"/>nitial letters can be images too
</p>
or, for that matter (and discounting the differences in break opportunities):
<p>
<img style="float: start; height:3lh" src="fancy-I.png"/>nitial letters can be images too
</p>
The same process applies to elements with display:inline-block
and other inline content generating its own formatting context (see also #4116)
To be resolved then: does use of an atomic inline within an initial-letters element automatically set the atomic inline's height?
5. More flexibility in initial-letters valuesThe initial-letters element itself takes two numbers, the first ("size") determining the font-size via quite a complex algorithm, the second ("sink") the number of lines to shift up and down - not directly, as shown in the hindi example above; it's more a statement of intention as to where the bottom of the drop-cap should be.
As it is now, the "sink" value must be a positive integer and defaults to the "size" value. I don't see why this limitation is required. Make it a number or length describing the vertical shift of the initial-letter. If specified as a number, treat it as if it had an implied "lh" unit. If undefined, the value depends on the baseline: for alphabetic, it's the same as "size", for hanging or hebrew it's 0. And allow it to be less than zero if that's what the user wants.
Why? First, (like @tabatkins I believe) I dislike unitless numbers; make them a length so you can do interesting things with calc(). Second, by making this number explicitly "the distance to shift the text" it removes any confusion around the fact that hanging
baseline text is dropped by default, whereas alphabetic
baseline text is not. It also opens up other alignment options, such as center
or mathematical
which might need finer adjusting (I can't think of a use for these, but I can't think of a reason to disallow it either). Finally, it's no harder to implement.
Thought of as a length, its functionality is identical to baseline-shift
. I'll leave that out there, perhaps greater minds than mine will have some ideas on reconciling the two. If there's an appetite to remove the "sink" parameter from initial-letters completely and replace it with baseline-shift
, I don't see why that wouldn't work.
The idea is you can have an initial-letter made up of more than just a single text node. It is described in the specification and even an example given, with image:
This corresponds to
<em style="initial-letters:2"><b>This</b> phrase</em> ...
While I think this isn't a bad idea, the problem will come with the font size. The spec states that initial-letter sets the used font-size only, not the computed size. Well, this becomes a problem when you have more than one element. The nested <b>
above would inherit the computed font size, not the used size: effectively it's getting the font-size of the parent block.
You could insist that font-size is calculated with the magic algorithm for the entire subtree, but that seems unnecessarily restrictive. I can't think of many situations where this would be an actual problem; there may be better examples in other languages, but in English the best I can do is:
<p>
<span style="initial-letters:3">1<sup>st</sup></span> November
has an initial letter with two font sizes, and a baseline-shift based on the font-size.
</p>
Frankly, for all the hoops you would need to jump through to fix this, you may as well just say that using the initial-letters
property on an element sets the computed font size, not just the used one. I'm not sure what problem the current specification was trying to avoid by not doing this, but I'm not sure it's worth it.
The spec explicitly allows to have width or height specified, and section 5.7.1 describes how to align content within this box if required, using text-align
or align-content
.
Personally I think this is a very bad idea. Inline, non-replaced elements do not take a width or height anywhere else in CSS, and I think there's no need to make them do so here. If you want to give the box a particular size, just use display
to set to inline-block
or inline-flex
. If you're setting initial-letters
on a <span>
this is trivially allowed; allowing limited values of display to be set on a ::first-letter pseudo-element is perhaps not an insurmountable issue either. I think this approach would be easier to understand and implement than describing some special, initial-letters only alignment rules for elements with display: inline
.
Once you've done all the above, you've reduced initial-letter from a special thing with complex layout rules, to not much more than a regular inline: positioned like an inline, excluded like a float. The only particularly special feature remaining is the font-size. For even more flexibility at the cost of virtually nothing from an implementers point of view, why not set the font-size to its magically calculated value when initial-letters is set, but allow the user to override this if they want? i.e. if they specify font-size
it is respected, but if it's left unset, its value is computed using the initial-letters algorithm.
I don't have a real use-case for this, but again I can't give a reason why it needs to be prevented. So why not?
SummaryLots there, but to sum up my suggestions would be:
shape-margin
on initial-lettersalignment-baseline
and baseline-shift
on initial-letters; use them as you would normally for inline content, and instead drop the initial-letters-align
property.initial-letters
the vertical distance to shift the letter (a length), rather than the number of lines the initial letter should sink (a unitless value). Set its default based on the initial-letters "size" and the alignment.width
and height
on initial-letters with display:inline
. If these are required, the user can use inline-flex
or inline-block
.RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3