Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Promote SVG Viewbox to a CSS property, extend to all transformable elements #7

Open
tabatkins opened this issue May 25, 2016 · 42 comments

Comments

@tabatkins
Copy link
Member

commented May 25, 2016

From @vidhill on May 19, 2016 14:0

First, original proposition, https://lists.w3.org/Archives/Public/www-svg/2013Dec/0080.html

Yes, I'm trying to bring this to the table again as it did not seem to get much attention/discussion the last time around.
-maybe being on Github will be more conducive to discussion..

I really agree with this proposal,
being able to modify the viewbox on a SVG element using CSS would allow for very useful applications of SVG in a responsive layout, (See Sara Soueidan's examples below)

Sara Soueidan has a very good article demonstrating a perfect need and use cases for this here: https://sarasoueidan.com/blog/svg-art-direction-using-viewbox/

There were some enthusiastic responses from some SVG heads..

@sdras Sarah Drasner Mail List Reply

@AmeliaBR Amelia Bellamy-Royds Mail List Reply

@jakearchibald Jake Archibald Mail List Proposal

Copied from original issue: w3c/csswg-drafts#128

@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 25, 2016

Yup, sorry about the request getting buried. I got swamped for a while and am trying to catch up on proposals.

Yes, viewbox should totes be a property; nearly everything in SVG should be. A simplified version that solely exposes none | <length>{4} would be utterly uncontroversial. I like, however, the bounds value, and having it be defined simply as the stroke bounding box is good. This is essentially just CSS shrinkwrapping (in theory, of course; it's different in practice).

@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 25, 2016

From @AmeliaBR on May 24, 2016 21:11

@tabatkins Are you able to move this issue to the FX repo? I'd like to keep any view-box spec under the (shared) responsibility of the SVG WG.

And if you do start drafting something, Tab, I'd be happy to review it. If you don't get to it, it's still on my eventual To-do list. Just buried under far too many other to-do's!

@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 25, 2016

From @bradkemper on May 25, 2016 13:46

Would this affect non-SVG stuff too? I'm no expert on this attribute, but it sounds kind of like a clip-path:inset() effect which also affects the element's instrinsic dimensions, causing it to be scaled so that the new dimensions are contained by the original dimensions. Is that something we want for plain old HTML too?

@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 25, 2016

@bradkemper I don't think so. This doesn't clip, either; viewBox just (a) from the POV of stuff inside the SVG, sets up the coordinate space they position themselves in (and in particular, what "100%" maps to), and (b) from the POV of stuff outside the SVG, defines the intrinsic aspect ratio of the element.

(a) doesn't mean anything for non-SVG elements. (b) could theoretically, but it's a very roundabout way to handle aspect ratio, and misses some features we'd like for a real aspect-ratio property, so I don't think we should try to smuggle aspect-ratio into general CSS via viewbox.

@BigBadaboom

This comment has been minimized.

Copy link

commented May 25, 2016

Animatable: as simple list of length

Is this flexible enough? Or should viewBox perhaps be considered a shortcut for

viewbox-x viewbox-y viewbox-width viewbox-height
@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 25, 2016

You can't specify those independently in SVG, and to the best of my knowledge people haven't asked for it (despite the handful of examples I've seen of viewBox animating), so I'm inclined to not do that unless there are good use-cases for it.

@AmeliaBR

This comment has been minimized.

Copy link

commented May 26, 2016

@BigBadaboom

I suggested making the min-x and min-y parts optional (default to 0), but I don't see any need for breaking it into shorthand & longhand properties.

And yes, it should be animatable as a list of 4 independent numbers. Being able to animate a viewBox with CSS animations/transitions is one of the main benefits for SVG of upgrading it to a property. (The other main benefits being media queries and assigning a single viewBox to a class of inline SVG icons.)

@AmeliaBR

This comment has been minimized.

Copy link

commented May 26, 2016

@bradkemper

For non-SVG content, the viewBox would:

  • Allow any content to scale to fit available space (e.g., fancy text headings, HTML poster ads).
  • Define an aspect ratio that could be used to reserve the correct height/width for embedded content (videos, images that haven't downloaded yet) in a responsive design.

I'm not sure how this relates to clip-path.

@sdras

This comment has been minimized.

Copy link

commented May 26, 2016

+1 on animatable, I think part of the reason it has only been done a handful of times is undereducation. It has a lot of nice implications for the web and informative graphics. 4 independent numbers makes a lot of sense. Thank you for all of your work, Tab!

@BigBadaboom

This comment has been minimized.

Copy link

commented May 26, 2016

My thought was that if animators wanted to use viewBox like a camera, they may want to animate position differently from size.

If it is an array of lengths, they could achieve that to some extent with @Keyframes. But I was thinking they may want to do something like:

.crash-zoom {
  viewbox-x: 100;
  viewbox-y: 100;
  viewbox-width: 16;
  viewbox-height: 9;
  transition: viewbox-x: 0.5s easeInQuad, viewbox-y: 0.5s easeInQuad,
              viewbox-width: 0.5s easeOutElastic, viewbox-height: 0.5s easeOutElastic;
}

@AmeliaBR

This comment has been minimized.

Copy link

commented May 26, 2016

@BigBadaboom I can see the use-case. But it's something that could be easily added in after the fact, so we don't have to worry about it now. Once we get authors are really using the property as is, then they can tell us if it isn't flexible enough without shorthand/longhands.

@vidhill

This comment has been minimized.

Copy link

commented May 26, 2016

+1 on animatable as well,

Great creative potential on animated viewbox.

Great to see this being discussed.

@jezmck

This comment has been minimized.

Copy link

commented May 26, 2016

+1

1 similar comment
@bodymovin

This comment has been minimized.

Copy link

commented May 26, 2016

+1

@jakearchibald

This comment has been minimized.

Copy link

commented May 26, 2016

FWIW my sketchy proposal was to allow this on html elements too. Is it a no-go? https://lists.w3.org/Archives/Public/www-style/2016Feb/0328.html

@AmeliaBR AmeliaBR changed the title Proposal: SVG Viewbox be controlled as a CSS propery Proposal: Promote SVG Viewbox to a CSS propery, extend to all transformable elements May 26, 2016

@AmeliaBR

This comment has been minimized.

Copy link

commented May 26, 2016

@jakearchibald Definitely a go.

Changed the issue title to reflect the beyond-SVG scope of the proposal. Apologies for ruining email threading of notifications.

@ubik23

This comment has been minimized.

Copy link

commented May 26, 2016

+1

@jakearchibald

This comment has been minimized.

Copy link

commented May 26, 2016

Y'all are great. Really excited about this.

@roblevintennis

This comment has been minimized.

Copy link

commented May 26, 2016

👍

@andrewpomeroy

This comment has been minimized.

Copy link

commented May 26, 2016

👌

@jesperstarkar

This comment has been minimized.

Copy link

commented May 26, 2016

👍

@shepazu

This comment has been minimized.

Copy link
Member

commented May 27, 2016

I wanted to use this 2 days ago to make a map zoomable onto different countries. Please, please, please let this happen. Let me know if I can help.

@tabatkins

This comment has been minimized.

Copy link
Member Author

commented May 27, 2016

Hmmmm, if it's usable on all transformable elements, what does that mean? It is a scale/pan based on the ratio of the viewBox width/height and the element's actual width/height? If we want to do that (make it a new transform shorthand), we need to define where in the list it goes, and then probably define a transform function for it.

@AmeliaBR

This comment has been minimized.

Copy link

commented May 27, 2016

@tabatkins Yep, the net effect can be described as a scale + translate, but only on the element's children, not on the element itself. Not sure whether it's practical to define it as a transform function, but it would affect the cumulative transformation matrix for child content. (I still want to get all the SVG transformation-related DOM APIs generalized to all transformable elements, too!)

Since there's lots of interest here, I'm copying my email from April which lays out a lot of the complications that will need to be addressed, as well as summing up possible use cases:


Support viewBox in CSS

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.

@Martin-Pitt

This comment has been minimized.

Copy link

commented May 27, 2016

One more reason for css-ified naming to view-box is that it exists as a keyword in clip-path

@nucliweb

This comment has been minimized.

Copy link

commented May 28, 2016

👍

@birtles

This comment has been minimized.

Copy link
Contributor

commented May 29, 2016

Can someone fill me in on where the view-box naming proposal came from? The original proposal was for viewbox (as linked in the first post) since otherwise we'll have viewBox for the presentation attribute in SVG, viewBox or viewbox when using SVG in HTML, and view-box when using CSS. It seems better to me to harmonize the between presentation attributes / property than with keywords in the clip-path property? (which could possibly still be changed if we really needed to) But maybe this has been discussed elsewhere?

@Martin-Pitt

This comment has been minimized.

Copy link

commented May 30, 2016

It's not been discussed anywhere else as far as I know.

I'm just chiming in a vote for view-box. Not to break apparent convention with CSS (no combined words, fooBar ‹-› foo-bar) and also being able to condense neatly back to element.style.viewBox, which matches original SVG spec more nicely than the lowercased HTML version.

@jarek-foksa

This comment has been minimized.

Copy link

commented Jun 6, 2016

I would suggest using simplified model where the only purpose of the the view box is to define a rectangular area of element's local coordinate system for the purpose of rendering. How that area should be transformed so that it fits into the viewport would be controlled by object-fit and object-position properties.

In this model every renderable element has a view box, either explicit (defined with view-box property) or implicit (computed from the bounding or viewport box).

The spec should stop telling people that the view box "transforms the local coordinate system" as it makes the whole concept much harder to grasp. The view box does not transform but rather is transformed by the matrix determined from the value of preserveAspectRatio (or proposed object-fit and object-position).

@AmeliaBR

This comment has been minimized.

Copy link

commented Jun 6, 2016

@jarek-foksa

That's a very good point. The object-fit property already has the scale-down and none options that limit the scaling effect, so that plus viewBox would automatically allow authors to choose whether & when they wanted a scale effect.

That doesn't require simplifying the model: it actually is exactly the same model proposed above, I just hadn't extrapolated out all the extra options that object-fit would introduce, compared to preserveAspectRatio.

I also recognize your concern about terminology. We need to clearly distinguish between a transformation on an element and the transformation on its child content created by the interaction of viewBox & p.A.R.

@jarek-foksa

This comment has been minimized.

Copy link

commented Jun 7, 2016

@AmeliaBR I just meant changing the mental model that is used in the spec to explain the concept of the view box, not altering the API. The current reasoning is that the primary purpose of the view box is to provide intermidate transformation. If I were to explain what viewBox on the outermost <svg> element does, I would rather do it this way:

  1. The children of the outermost <svg> element live in an abstract infinite 2D space called the world space. Coordinates, distances and dimensions in this space are expressed with abstract (made-up) units called the world units (more generally known as user units).
  2. Since the world is infinite, it can't be rendered anywhere on the screen. What actually gets rendered is a finite rectangular area of the world called the view box, defined by the viewBox attribute on the outermost <svg> element.
  3. The screen area into which the view box is rendered is called the viewport, defined by the width and height attributes on the outermost <svg> element and/or by other CSS properties.
  4. The algorithm used to transform the view box so that it fits into the viewport is specified by the preserveAspectRatio attribute.

I realize this is a very limited explanaition that covers only one specific use case of viewBox and ignores all the edge cases (viewport with overflow: visible, relative units, etc.), but I hope you get the point.

@AmeliaBR

This comment has been minimized.

Copy link

commented Jun 14, 2016

Another issue that this spec should address: interaction of viewBox with box-sizing. Currently if you add box-model properties (margins, paddings & borders) to the root <svg>, auto-sizing gets thrown off when you embed that SVG as an <object>, <img>, etc.

@OliverJAsh

This comment has been minimized.

Copy link

commented Jun 14, 2016

I have one use case in mind that I'm not sure this will fix: a <picture> element with multiple <source>s, wherein each source image has a different aspect ratio. You want to reserve space for the current selected image, so there needs to be a way of defining aspect ratio for each <source>. I think this is a pretty significant use case—otherwise there's literally no way you can use art direction without causing the page to jump around as images load (as I found out the hard way).

The way I was imagining this (before hearing of this proposal) was:

<picture>
  <source media="(min-width: 500px)" srcset="landscape.jpg" aspectratio="4:3" />
  <source srcset="square.jpg" aspectratio="1:1" />
  <img>
</picture>

Is there any way we could utilise the proposal here to solve this use case? I can't think of one, because the browser re-uses the <img> element, so one can't simply apply a viewBox to each <source>.

@AmeliaBR

This comment has been minimized.

Copy link

commented Jun 15, 2016

@OliverJAsh That is an interesting & important use-case that hasn't been discussed yet.

Setting values on <source> to affect the associated <img> only when the source is used wouldn't fit with standard CSS property inheritance model, regardless of whether we used viewBox or a new property. However, it is actually somewhat similar to the case of SVG <view> elements: when the view is the target element of the URL, the viewBox on the view element replaces the corresponding property on the <svg>.

That doesn't mean it's an easy problem to solve (it's one of the main reasons SVG 2 hasn't turned viewBox into a CSS property yet), but if we solve it for one case we could solve it for both.

@dbaron dbaron changed the title Proposal: Promote SVG Viewbox to a CSS propery, extend to all transformable elements Proposal: Promote SVG Viewbox to a CSS property, extend to all transformable elements Jun 27, 2016

@frivoal

This comment has been minimized.

Copy link

commented Jul 13, 2016

I'm thinking of using this for scaling down large tables that otherwise don't fit when scrolling is not an option. Think of printing a w3c spec with a large propdef table at the bottom, on a piece of paper too narrow for it to fit. I think it would work, except that I'm just missing one thing: I'd need to set the view-box width to the intrinsic width of the table, rather than an arbitrary size.

table.propdef {
  view-box-width: max-content; /*I need the extra keyword*/
  max-width: 100%;
  object-fit: scale-down; /*If we make that an independent choice*/
  view-box-height: auto; /*Can I do that? If not, why not?*/
  height: auto;
}

Thougths?

@AmeliaBR

This comment has been minimized.

Copy link

commented Jul 13, 2016

@frivoal

That's an interesting use case. For auto-sizing view-boxes, I'd only been thinking about the SVG case (fill-box or stroke-box), where the size can be determined explicitly from the contents independent of the container size.

However, applying a viewBox to a CSS box would effectively remove all external constraints on its internal layout. (You want it to lay out its contents, then you'll scale them to fit.) So you need to be able to specify how it should constrain that layout intrinsically (min-content or max-content).

I think that makes perfect sense to allow those keywords in the width/height portion of the view-box. What the view-box is defining is the width and height values that will be used for laying out child content, before scaling (or not) to fit in the actual width and height assigned to this box.

We'd have to think through the interaction of width, max-width, and view-box-width, but it's definitely do-able.

@sdras

This comment has been minimized.

Copy link

commented Jul 13, 2016

That is incredibly interesting and I could see a lot of uses for it. I think this could be a really giant leap for responsive dev.

In terms of the view-box-height, if I remember correctly, the current SVG spec doesn't support height: auto. Most browsers will interpret it correctly regardless but I've seen issues on IE or mobile safari. I defer to Amelia on that one though.

@AmeliaBR

This comment has been minimized.

Copy link

commented Jul 13, 2016

@sdras
The latest specs should be clear on auto height/width for <svg> now, for controlling the layout box dimensions based on the viewBox proportions. We don't have any way to specify auto values inside the viewBox itself yet, to determine the necessary dimensions based on the bounding box of the actual graphics.

@sdras

This comment has been minimized.

Copy link

commented Jul 13, 2016

Ah, excellent. Thank you for the clarification.

@pkra

This comment has been minimized.

Copy link
Member

commented Jul 14, 2016

@frivoal 's use case also comes up for mathematical content; in fact, the MathML spec allows overflow="scale" though afaik there are no MathML implementation supporting it (for the web anyway). Having this in CSS would be great for all math rendering on the web.

@frivoal

This comment has been minimized.

Copy link

commented Jul 14, 2016

@pkra Yes, thanks for reminding me of the math use case. I'm running into it as well, and I agree that the same approach should be helpful there as well.

@frivoal

This comment has been minimized.

Copy link

commented Jul 14, 2016

@AmeliaBR Glad you like it. I was hoping you would, but kind of worried you'd show me how I completely misunderstood the whole thing:)

The interation between view-box width and max-width don't worry me too much. They have to be defined, but I don't think it's that bad.

I think we'll also need to be a bit careful about how that interacts with fragmentation, especially when the height / view-box height is auto. But that too seems just a matter of writing things properly, not a fundamentally hard issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.