Re: Support viewBox in CSS

[Copying the SVG mailing list, since this discussion affects them most of
all.  For www-svg subscribers, you may want to start by reviewing Jake
Archibald's message from 28 February "object-fit/view-box for element
content", archived here*:
https://lists.w3.org/Archives/Public/www-style/2016Feb/0328.html
*I think. The archives are currently down, or too slow for my very slow
connection.]


I am also strongly supportive of converting the SVG viewBox attribute into
a property controllable by CSS.  I also like Jake's proposal to extend it
to the CSS box model as a way of creating aspect ratio control and
scale-to-fit behavior for HTML content.

It's taken me this long to reply because I wanted to carefully outline some
of the issues that need to be considered.  This is also effectively an
explanation of why we haven't done this yet in SVG.

It's getting a little late to spec this in time for SVG 2.  However, if
there is support from the CSS WG to also adopt this feature for CSS box
layout, then it probably makes sense to have it as its own module, anyway.

(Aside: I agree that the CSS-ified term should be `view-box`. I'm using
`viewBox` here out of habit. I'd assume it would continue to be the
standard spelling for the presentation attribute.)

First, a summary of what the SVG viewBox and preserveAspectRatio attributes
do, translated into CSS terms:

- viewBox defines an intrinsic aspect ratio for the element.  This
intrinsic aspect ratio is used to resolve `auto` height or width width
proportional to a fixed value in the other dimension.

- viewBox defines default height and width in pixels for the element,
although this currently only has an effect when specified on the root
element of an SVG file that is embedded as an image.

- viewBox + preserveAspectRatio together create a scale + translate
transformation for the element's _child_ content.  They do not affect the
position or scale of the layout box for the `<svg>` itself.

- viewBox (in most but not all cases) establishes the basis for 100% width
and 100% height for SVG layout of all child elements.  More generally, it
defines the px-to-percentage ratio.

The scale transformation is not defined as an explicitly magnification
factor, like in transform: scale(s).  Instead, it's always a scale-to-fit,
with the preserveAspectRatio attribute defining what "fit" means when the
`<svg>` layout box is constrained to a different aspect ratio than that
declared by the viewBox.  preserveAspectRatio therefore has much the same
function as CSS object-fit and object-position combined (albeit with more
limited options).

The translate transformation is a combination of an implicit transformation
from the preserveAspectRatio (the corner of the viewBox won't always fit up
against the corner of the layout box) and an explicit transformation
defined by the xMin and yMin parameters of the viewBox.  These are often
left as 0 (no explicit translation), but they are very useful in some
cases, such as creating a centered coordinate system.

So, if I was going to write up a proper spec for viewBox in CSS (as I keep
telling people I intend to do), I would make the x- and y-offset parameters
optional, and I would replace preserveAspectRatio with object-fit and
object-position.  (The mapping of attribute values to those properties
could be defined via user stylesheets.)  Currently, these object-*
properties are not well defined for `<svg>` elements anyway, and interact
poorly with preserveAspectRatio.  It makes sense to create a single
cohesive definition, with all the extra options that object-* properties
provide.  Jake's proposal introduces a new property, but I don't think it's
necessary.

Benefits for SVG:

- Allow viewBox to be animated via CSS animations & transitions.  This is
an important part of making declarative animation via CSS a comprehensive
alternative to SMIL.

- Allow viewBox to be controlled by media queries.  This is essential for
creating responsive SVG designs.  SVG 2 geometry properties and CSS
Transforms allow the layout of shapes to be adjusted for different media,
but that is of limited use unless the overall dimensions of the graphic can
also be adjusted.

- Allow a common viewBox to be specified once for many different `<svg>`
elements within a document (e.g., for SVG icons in an HTML file), reducing
markup and repetition.

Complications for SVG:

- When an SVG file is an embedded document (e.g., `<img>` or `<object>`),
the viewBox is often used to determine how much space in the main document
it should consume (by defining the intrinsic aspect ratio & size).  This in
turn affects the "media" for all media queries defined within the SVG
file.  If those media queries can alter the viewBox, you could generate
infinite loops & there would need to be clear rules on how to resolve them.

- Only certain elements currently accept the viewBox attribute (svg,
symbol, pattern, marker).  Only some of these (svg, symbol) are "viewport
elements" that re-define the px-to-percent ratio.

  If viewBox became a generic property that you could specify on any
element (by setting it to a value other than `auto`), it would need to
create a consistent behavior as a layout container for child content.

  I personally think it's one of the biggest mistakes in SVG that patterns
& markers _don't_ reset the meaning of percentage lengths (it makes
percentage lengths pretty much useless within pattern and marker content).
There has been some talk of changing this in the SVG 2 spec, but it would
be a breaking change & we haven't made that resolution.  I would also like
to see viewBox available on `<clipPath>` and `<mask>`.  I don't mind
allowing it on generic SVG container elements (`<g>` and `<a>`),
effectively giving them the same layout model as a nested `<svg>`.  The
other parts of the layout model, `x`, `y`, `width`, and `height`, have all
been made geometry properties in SVG 2, although they currently would not
have any effect if declared on a `<g>` element.

  A nested `<svg>` element, even without a `viewBox` attribute, redefines
the coordinate system for child elements.  In other words, it resets the
percentage-to-px ratio and creates a translation based on the value of `x`
and `y`. Therefore, there would need to be both a `view-box: auto` value
(default for SVG elements that normally take a `viewBox` attribute) and a
`view-box: none` value (initial value for the property and default for all
other SVG container elements).

  These changes would require coordinating changes to SVG DOM properties
that allow you to access the nearest ancestor viewport element for any SVG
element.  They need to either (a) be redefined to retrieve the nearest
ancestor `<svg>` or `<symbol>` element, independent of any notion of
viewBox or the basis of 100% or (b) be redefined to find the nearest
ancestor whose computed value for `view-box` is not `none` (more useful,
but more work for the implementation). Implementations would also need to
update how they resolve percentage lengths.

- The `<use>` element has special rules for how width & height values on
that element interact with width, height, and viewBox on a re-used `<svg>`
or `<symbol>` element.  These rules would need to be updated & generalized
to any element with a non-none computed value of `view-box`, and
implementations updated correspondingly.

- SVG currently has other ways to set the viewBox on an `<svg>` element,
the `<view>` element and the `#svgView()` fragment, which are not easy to
represent in CSS.  When a view is in effect, the effective `viewBox` and
`preserveAspectRatio` values for the `<svg>` element are over-ridden by
those specified in the view.  This shouldn't be a deal-breaker, though,
since you can also specify `transform` via those means, so any
implementation is already going to have to propagate transform styles from
the view to the SVG.  It's just an extra headache & confusion to be aware
of.

- Although it's not currently specced, a common request for SVG has been
the ability to automatically generate a viewBox based on the bounding box
(fill-box or stroke-box) of its child contents.  This would scale whatever
graphic you have to fill the available space, without the author needing to
calculate the exact bounds of the graphic.  This is _different_ from the
`auto` value I've described previously (the current behavior of an SVG if
you don't specify `viewBox` attribute), which creates a view-box based on
the width and height in pixels, and therefore does not apply a scaling
effect.


Benefits for CSS box model:

The main benefit as noted in Jake's proposal would be aspect ratio control,
for videos, for images that haven't been downloaded yet, and for complex
graphical layouts.

There have been a number of different proposals on www-style lately for
aspect ratio control.  Currently, the "padding hack" is the only way to
create a scalable container with a fixed aspect ratio (and it can only be
used to scale height to match width and not the reverse).

The scale-to-fit effect of viewBox would be also useful for big text
headers and for embedded `<iframe>` (e.g., the little scaled-down preview
iframes used on CodePen).

Complications for CSS box model:

The `view-box` approach would not be quite as flexible as other proposals
for aspect ratio control, since it can't separate the aspect ratio from the
scale effect.  Most of the use cases (video, image, and big-text headers)
are all scale-to-fit.  But there could be other cases, such as
text-in-a-shape layouts, where you would want the box to maintain a certain
aspect ratio but not scale the text.

The xMin and yMin offset parameters are less useful for CSS (at least,
until polar coordinate layout gets adopted).  If we make them optional that
isn't a big problem, but would need to define the behavior if they are used
(e.g., the impact on the interpretation of left/top/etc in absolute
positioning, on transform-origin, and so on).


All in all, I do think it's a useful proposal, but there are a lot of
details to sort out.  I would be happy to help spec it, but I probably
won't have much time to work on it in the next few months as we try to get
SVG 2 and the SVG accessibility specs finalized.

~Amelia Bellamy-Royds



On 4 April 2016 at 20:24, Sarah Drasner <sarah.drasner@gmail.com> wrote:

> Hi,
> I would like to support Jake Archibald's proposal,
> https://lists.w3.org/Archives/Public/www-style/2016Feb/0328..html#options3 to
> move the viewBox, or view-box, as stated in the proposal into the CSS spec.
> Currently if you need to adjust the viewBox for responsive development,
> which is a very useful use-case, you have to use JavaScript for the
> behavior of a simple media query. Using a CSS media query would be nice in
> a multitude of implementations, including but not limited to SVG sprites or
> Infographics. I've written an article for a few ways of working with it
> here:
> http://www.creativebloq.com/web-design/how-create-animations-scale-all-devices-31619478
>
> Thanks for your time and attention.
> Best wishes,
> Sarah
>
> --
> Sarah Drasner
> *http://sarahdrasnerdesign.com/ <http://sarahdrasnerdesign.com/>*
>
>

Received on Tuesday, 12 April 2016 17:40:01 UTC