Adobe

decor

Web Platform Team Blog

Making the web awesome

Using HTML for Rich Media Advertising

As web technologies like SVG, WebGL, and Canvas continue to get richer, more expressive, and better supported, it makes sense to start turning to them more frequently for common rich media solutions like advertising. That’s why, when the Adobe Web Platform team got the opportunity to sponsor CodePen for February, we decided to make a self-referential ad that uses SVG technology to promote SVG technology. Here’s what we came up with:

Specifically, the ad promotes a project called Snap.svg, a relatively new open-source SVG JavaScript library (think of it as a super lightweight version of jQuery, but for creating, animating, manipulating, and querying SVG content). And, of course, all the animations in the ad are done with Snap.

While creating the ad, we were happy to find that the designer/developer workflow was really smooth since we were able to maintain a vector workflow throughout. Designing the storyboard and artwork in Illustrator not only allowed us to maintain a clear vision of what the end result would be, but it also allowed us to generate vectors that could be used directly by Snap. The final step was to integrate Snap for animating and manipulating the SVG, resulting in the final creative.

Another big advantage of SVG is that we essentially got responsiveness for free. The ad can be served in any size iframe and it will automatically scale and look perfect. That gives the publisher (in this case, CodePen) maximum freedom when it comes to displaying the ad, and it means that the creative looks (and works) great in both desktop and mobile browsers.

If you’re doing rich media work on the web, I highly recommend that you go check out Snap.svg. And if you want to learn more about how the ad was put together, feel free to check out the source code.

Observations from the CSS Working Group Meeting

Seattle-Exterior1-465x145

Two weeks ago I had the opportunity to attend the CSS Working Group meeting in Seattle. I am not an official member of the Working Group and so couldn’t participate in the discussions. I was able to observe and see how the next generation web technologies are made.

The meeting lasted three full days and was held at the Adobe Seattle office. The weather was rainy and overcast. The setting was beautiful. And the discussions proved to be the best attraction of all. Many of the members have been working together for over a decade. It is clear they have developed some strong bonds and mutual admiration for one another’s technical opinions and expertise.

On the first day of the meeting, a schedule is set by allocating a time slot to each topic, the duration of which is estimated on a case-by-case basis. As topics come up, one person often takes the lead in explaining the context and the proposal at hand, and others chime in with opinions and questions. In most cases, consensus is reached without much difficulty. On some topics however, strong disagreements may exist, and ultimately, a vote is required in order to gauge the group’s consensus. This happened a couple times, but in all cases an overwhelming majority of attendees supported a specific proposal, with just a couple of people dissenting or abstaining from the vote altogether.

A significant amount of progress was made at the meeting on a wide range of specifications. To name just a few:

  • There was a good discussion around media queries
  • Some bugs were resolved
  • A decision was made to add mathematical operators to the syntax (i.e., width < 700px), even though it would have to be escaped in XML
  • There was a lively discussion that resulted in a decision to expose shape reference boxes in SVG
  • An agreement was reached to poll web authors as to whether to use ! or :has() in CSS

Much more was covered as well, all captured in the publicly available CSSWG Minutes Seattle F2F.

It was truly fascinating to witness the technical debates and hear different members stake out their philosophical and technical positions on specific topics. The discourse always remained civil. While at times it seemed as though topics veered off track, in the end, issues were resolved one way or another.

The biggest takeaway for me was the dedication the working group members have in finding the best technical solution for the web. This one meeting was just the smallest of drops in the huge bucket of effort that the group as a whole, and each member individually, has devoted to moving CSS specifications forward. It was very encouraging to see that all of the attendees genuinely cared about the future of the web as a platform, and displayed an admirable level of effort and patience in order to make it a reality. I came away feeling confident that the right balance was being struck on the next set of feature specifications and that CSS was in good hands.

New CSS Shapes Syntax

The CSS Shapes specification has moved to Last Call. This move has brought a whole host of syntax changes, and we have updated the Blink and WebKit implementations accordingly. Read on for a summary of what has changed in the specification.

Note on the examples

If you wish to view the examples live on CodePen when reading this article, you need to get a browser that supports CSS Shapes and make sure they are enabled. If that sounds interesting, take a look at our browser support page, which will tell you which browsers support Shapes and how to enable it.

Box values

You can now define shapes based on the CSS Box Model of the element the shape applies to. The shape can be declared as the margin-box, border-box, padding-box, or content-box. This shape conforms to any border-radius that has been specified on the element. And if you would like to take a look at CodePen, there is an example of the box values being used as shapes.

box values example

Basic Shapes with box values

You can also specify a box value along with a basic shape. This box value is referred to as the reference box for the shape. This causes the basic shape to use that box instead of the default box to determine things like sizing and position of the shape. The default box depends on which property you are setting the value for: shape-outside defaults to margin-box, while clip-path defaults to border-box. For example, the following two properties could define entirely different circles depending on the margin, padding, or border that is applied to the element:


shape-outside: circle();

shape-outside: circle() content-box;

If you don’t understand the use of circle() here, don’t worry. The next section covers all of the shapes and the changes that apply to them.

Basic Shapes

Basic shapes are at the core of the CSS Shapes module. Most of the shapes have been changed from a SVG-style syntax to one more in line with other CSS properties. With the exception of polygon, all other shapes have undergone significant alterations.

rectangle and inset-rectangle are now inset

A single shape, inset, has replaced the rectangle and inset-rectangle shapes. This shape defines a rectangle with sides that are inset from the sides of the reference box by a given amount.

Basic inset syntax

The basic syntax for inset is like that of the margin shorthand. If you supply one argument, then that argument specifies the inset for all four sides of the rectangle:


inset(value)

If you specify two arguments, the first argument specifies the inset for the top and bottom, while the second argument specifies the inset for the right and left:


inset(top_bottom right_left)

You can also specify three arguments, where the first argument specifies the inset for the top, the second argument specifies the inset for the right and left, and the third argument specifies the inset for the bottom:


inset(top right_left bottom)

Finally, you can specify four arguments, in which case, each argument specifies the inset for a different side, like so:


inset(top right bottom left)

There are some live examples of inset with different arguments on CodePen.

inset examples

Rounding the corners

It doesn’t stop there! You can take any of the forms above and add the round keyword and then use the familiar border-radius syntax to define rounded corners for the resultant rectangle. A very simple example:


inset(30% round 10%)

Of course you can do more complex things:


inset(10% round 10% 40% 10% 40%)

You can see the following more complex inset shape examples live on CodePen.

inset with rounded corners example

circle and ellipse - same names, different arguments

Both circle and ellipse are still with us. However, the arguments they take have changed significantly.

How to specify radii

To start, radii are no longer exclusively lengths or percentages. There are two new keywords that can be used to define the radii: closest-side and farthest-side. Both of these keywords refer to the distance from the center of the shape to a side of the reference box.

closest-side

closest-side uses the distance from the center of the shape to the side of the reference box that is closest to the center coordinate of the shape. In the case of a circle, this is as simple as measuring the distance between the center of the circle and each side of the reference box and using the minimum distance. It is a little more complex in the case of an ellipse, since the ellipse has two radii: one in the horizontal direction (rx), and one in the vertical direction (ry). To compute the closest-side value for an ellipse, only the sides in the direction of the radius in question are considered. For example, to find the closest side for ry, you would only compare the distances between the center and the two sides in the vertical direction.

For example, circle() is the same as circle(closest-side), which defines the largest circle that will fit within the reference box. And ellipse() is equivalent to ellipse(closest-side closest-side), defining the largest ellipse that will fit within the referemce box. You can see the following example of circles and ellipses defined with closest-side live on CodePen.

circle and ellipse example

farthest-side

farthest-side is analogous to closest-side, it just looks for the distance to the side of the reference box that has the largest distance from the shape’s center. Just like with all of the previous examples, you can see the following circle defined with farthest-side on CodePen.

circle farthest-side example

How to define the center

It isn’t just radii that have changed. You now can use the full CSS position syntax to define the center of the shape. This is done by including the at keyword and following that with a position, like so:


circle(closest-side at center)

And yes, this example of a positioned circle is available on CodePen.

positioned circle example
If you read the previous section, you might realize that the result looks exactly the same as the example for circle(). That is because this is the full expansion of that shorthand. Note that circle(at center) is yet another way to say the same thing. All of the arguments are optional, and they all have defaults.

You can of course position an ellipse or circle at a different point than the center. It is beyond the scope of this article to cover all of the options here, but I can give a few examples.


ellipse(at top 50% left 20%)

circle(25% at 25% 50%)

If you would like to play with this or see it in action, you can check out the positioned ellipse and circle example on CodePen.

positioned circle and ellipse example

How do I use these shapes?

The CSS Shapes specification defines a shape-outside directive that changes the wrapping behavior of floats so that content can wrap around an arbitrary shape. All of the examples in the previous sections use shape-outside. In addition, these shapes can be used with the clip-path property, from the CSS masking specification. If you look closely at all of the examples used in this article, they all use the clip-path property to visualize the shape.

Further reading

This article has just covered some of the largest changes that have come with the move to Last Call. Future blog posts will cover use of these shapes and the other shapes types defined in CSS Shapes in more detail. If you can’t wait, you can always take a look at the CSS Shapes specification for the authoritative take.

Baseline Grids for the Web

Visual design often has a vertical rhythm, laying out text and graphics at regular vertical intervals. This makes side-by-side content line up nicely. In printing this allows lines of text occupy the same vertical position on either side of the page, to prevent your eye from noticing any ink showing through thin paper.

A vertical rhythm is accomplished by using a baseline grid, either implicitly or explicitly. In traditional publishing, you can implicitly use a baseline grid by using consistent leading and fiddling with any exceptions that arise. Or there are tools that help you set up an explicit baseline grid. On the web, fiddling with exceptions isn’t something you can (or should) do. So the implicit option just doesn’t work. And the web has so far lacked an explicit baseline grid.

Here’s an example of why you might want to use a baseline grid. This site has three side-by-side article summaries. Headings and body text have slightly different line heights, and different screen sizes will produce different numbers of lines for the headings. So the body text from each summary does not line up with the others.

1.1.without-grid

It’s a bit easier to see what I mean if I add some lines to the picture. If all of the body text aligned its baselines to the green lines, the side-by-side content would share a vertical rhythm and look less sloppy.

2.1.grid-overlay

You can (usually) achieve a consistent vertical rhythm today by forcing all line heights to be strict multiples of the body line height. The site I pulled this example from actually does try this. The heading and body text in their summaries use exactly the same line height. So the headlines are a little too tightly spaced and the body text is a bit too loose. And unfortunately, other elements on the page mess with this consistency, so the body text doesn’t line up anyway.

3.1.align-everything

It’s generally better to specify slightly larger line height for larger text, but then you can’t have everything line up to the baseline grid, or you get something like the result above. So in order to use an explicit baseline grid, you need to be able to say that some parts of the design snap to the grid, and other parts ignore the grid. If you only align the body text, you get this result, which is a bit better than the original.

4.1.align-paras

Then you can start playing with having blocks align to the grid as well as text lines. Each heading can be considered as a block of lines that can interact with the grid as a unit. Perhaps you’d like the first baseline of each heading to align with the grid:

5.1.first-line-block

Or you could have each heading center all of its content in-between two grid lines:

6.1.center-blocks

The differences between the last two are subtle, but aligning the first baseline gives you better side-by-side consistency in the headings, and centering gives you more consistent spacing between the headings and the body text. Which to choose depends on the design you’re trying to express.

I believe that CSS needs an explicit baseline grid feature, and am now working with the CSS Working Group to figure out the best way to define and use a baseline grid in web design.

Improving text selection in CSS Regions – take 2

It’s been three months already since our last update on the work our partners at Igalia contributed to improve text selection for pages that use CSS Regions. In the meanwhile, a good amount of progress has been made, both in terms of clarifying the expected behavior and actual implementation work in WebKit and Blink.

If you’re in a hurry, here’s why this matters: Currently, the way text selection on the web is specified, lacks the flexibility needed to make it behave intuitively in modern web design. Not only that, but CSS features (like Flexbox or Regions) that break the direct mapping between elements in the document and the actual content rendered on the screen may yield highly unexpected results for the end-user. Thus, discussing the possible standardization solutions and implementing them is important for creating a more usable web.

You can head over to Javier’s and Rego’s blog posts for all the nitty-gritty details (and a smooth video :) ) of the fixes needed in WebKit. Hopefully they will make their way into the WebKit trunk, providing pages that use CSS Regions better and more intuitive text selection behavior.

Better SVG for a better web

Thanks to support by all major browsers, and an increasing variety of devices and screen resolutions, SVG’s built-in responsiveness is attracting much attention and exploration. Most recently, Lonely Planet has worked on moving from icon fonts to SVG. One notable motive for the switch was the ability to style SVG with CSS. Several sites offer SVG icon libraries e.g. helveticons, thenounproject, or even maps. Others in the community explore animated line drawing, the use of SVG as a scalable sprite format and even to build web application UI.

Though SVG markup is often tweaked by hand for styling and scripting, authoring raw markup is not an effective way to build graphic design. Designers typically use graphic editors to easily define and adjust all the shapes and components of the final image. Though few editors use SVG as their core format, most of them are able to import and export it. This is the case for Adobe Illustrator, which started exporting SVG in 2000.

As more web designers consider SVG for their graphic content, Adobe wants to make sure Illustrator’s SVG support is relevant to their growing needs. The web platform team is actively working with the Illustrator team to improve the SVG we generate around a few dimensions:

  • Clean, modern output: though valid, Illustrator’s output reflects an era when DOCTYPEs, for instance, were a requirement. Beyond outdated practices, some of the generated attributes or elements can sometimes be redundant. Though we do not expect optimizers such as SVGO to become unnecessary, we intend to save them some work over time.
  • Easy to style and script by default: while SVG supports multiple ways to achieve the same visual result, some of them are less friendly to subsequent CSS and JavaScript coding. For instance, a element positioned using a transform matrix() function is harder to re-position or animate from CSS or JavaScript than if it were positioned using the x and y attributes. Other potential work in this area includes improving the conversion of object or layer names to IDs, as well as generating more reusable style rules applicable using CSS classes.
  • Better accessibility: though making SVG accessible is currently an area of evolving standardization, we can make it easier to author accessible SVG.

Our joint work has just begun but a few changes are already visible in the latest update of Illustrator CC:

  • When Saving As SVG, Illustrator no longer defaults to Adobe CEF for fonts.
  • The SVG code for the selected object(s) is now copied to the clipboard by default, ready to be pasted in your web editor.
  • The default precision for length values is now 1 (used to be an unnecessarily precise 3).
  • A new option called ‘Responsive SVG’ no longer gives your SVG image a specified width and height; this allows the image to scale to the size of its container by default.
  • Last, we addressed an issue that prevented pixels from snapping to the grid when an SVG document created with Illustrator was reloaded for editing. Also, paths that snapped to the pixel grid when your SVG was viewed in browsers could look blurry in Illustrator. This was especially visible when designing small, simple high-contrast objects like icons.

We are only getting started. There is much more to come. In the meantime, we would love to hear from you. Use the comment section or ping us on Twitter at @adobeweb.

Create shapes with CSS box properties demo

Hans Muller reviews the box shape geometry involved in specifying CSS Shapes as a CSS box. You can generate many shapes by referring to edges in the CSS Box Model. But, as Hans put it in an early post, “You must remember that the CSS Box Model is a set of four rectangular Russian dolls.” In this latest post, Boxed Into Corners: Shapes, Boxes, and Corner Radii, Hans goes into detail about how these nested boxes effect and constrain each other.

And at any point, if the details become obscure, just scroll down to the demo, and try out some use cases for yourself.

boxed_into_corners_lo_res

Making the Web Sweeter with Food Network and Cupcakes

There are two things we know for sure that almost everyone loves: mobile applications and cupcakes. Food Network brought the two together in a beautiful tablet application called, appropriately enough, Cupcakes! (check it out on Apple’s App Store). Cupcakes! is kind of a cupcake encyclopedia, full of recipes, ideas, tips, and of course, inspirational cupcake photography.

When we saw the Cupcakes! app, we wanted to see if we could use some of the newer web platform features to bring the same type of experience to the open web. Food Network is always looking for more ways to engage their audience, so they agreed, and we teamed up.


Canvas Blend Modes

The first thing you see when you open the Cupcakes! demo is a giant cupcake. Watch carefully and you’ll see that the frosting changes colors using the power of canvas blend modes. Blend modes allow us to define how layer colors interact with each other. It works the same way layer blend modes work in Photoshop, creating more complex color combinations than opacity provides. In this case we’re using the blend mode color-burn by setting the globalCompositeOperation property like this:

context.globalCompositeOperation = 'color-burn';

blending

You might have also noticed that the color conforms to the shape of the frosting. That’s because we’re masking the color with another image that represents the shape of the frosting. We’re able to achieve this effect with compositing, which allows us to define the visibility of one layer based on another. This is also achieved with the globalCompositeOperation property, but with the value destination-atop, which tells it to mask, or “cut out,” the bottom layer based on the top layer’s alpha channel.

context.globalCompositeOperation = 'destination-atop';

compositing

There are a variety of values that can be used with globalCompositeOperation. These can be applied in very creative ways to make a huge number of interesting visual effects.

Learn more about blend modes and compositing.

CSS Masks

We’ve seen how we can mask content in Canvas, but sometimes it is useful to mask semantic markup like images or other HTML content. This can be achieved with CSS Masks. CSS Masks are alpha masks: images whose alpha values are transferred to the underlying content. The syntax is identical to that used with the background-image property, which means we can size, position, repeat, and even apply multiple masks to the same element. We use masks throughout the demo to add a subtle texture to content like the navigation buttons.

mask

Learn more about CSS Masking.

CSS Clip Paths

If you’re familiar with Photoshop, you probably know there are two kinds of masks: layer masks (which in Photoshop is a luma, or black & white, mask), and vector masks (composed of a vector shape that cuts out your layer). While CSS Masks are more akin to layer masks, CSS Clip Paths are the web’s version of vector masks.

We can use Clip Paths to mask parts of our content with CSS or SVG shapes. This allows us to reuse a frame for content throughout the site simply by applying a class without the need for images. It also gives us the ability to shape user-submitted photos without having to perform server side image manipulation. Clip Paths support CSS Transitions and Animations as well so we can animate the path of the mask from one shape to another (assuming the vertices of the vector shape match up). This technique is used throughout the site on the starburst buttons as well as the timer and menu.

Learn more about CSS Clip Paths.

clippath

Dynamic Masks

CSS Masks and Clip Paths are extremely powerful, as are the different ways we can animate them. But sometimes it’s useful to be able to draw masks dynamically with code. The easiest way to do this would be to draw and animate a canvas and use that as a mask. There is a way to do this in WebKit browsers (or formerly WebKit browsers like Chrome), though it is currently not standardized. Using the getCSSCanvasContext method, we can get a Canvas context that can be referenced from CSS. As parameters, the method takes:

  1. The context type.
  2. An identifier to be referenced from your CSS.
  3. The width and height of the canvas.

document.getCSSCanvasContext(‘2d’, ‘myCanvasId’, 100, 100);

You can then use it just like any CSS image and apply it as a mask:
-webkit-mask: -webkit-canvas(myCanvasId);

We are using this technique to create masked transitions between sections of the site.

dynamicmasks

Regions

If you’ve tried cooking from a recipe on your computer, you probably know it can be difficult to read the small type. It can also be easy to lose your spot when going back and forth from cooking to the screen. To solve this problem, we created a full-screen view you can access from the recipe page. We use regions to dynamically generate large slides that make it easy to both navigate the content, and to read it from a distance.

For obvious reasons, we didn’t want individual paragraphs (typically separate steps in the recipe) to get broken up across multiple slides. To achieve this, we’re defining how the paragraphs break within regions through CSS. By setting the break-after property to “always” on our paragraphs, it will always break our content into a new region after a paragraph tag.

-webkit-region-break-after: always;

Because the content can be variable length, and because we generate the slides dynamically from the content, we need to determine how many slides are required to display the entire recipe. We can do this by getting access to our flow from JavaScript, and generating regions until our overset property is false:

var myFlow = document.webkitGetNamedFlows().namedItem('recipeFlow');

if (myFlow.overset == true;) {
	//add another region
} else {
	//no more regions needed
}

regions

CSS Shapes

Cupcakes! makes subtle but important use of CSS Shapes (for a more conspicuous demonstration of CSS Shapes, see Using CSS Shapes to Enhance Visual Storytelling). CSS Shapes allow us to have text wrap either inside or around both standard shapes and custom polygons. It can make the layout of text look more polished and better integrated with its surrounding content as in this paragraph that flows around Alton Brown’s headshot:

Screen Shot 2014-01-09 at 3.01.30 PM

We also use CSS Shapes to make sure captions don’t overlap with background images as in this example:

Screen Shot 2014-01-09 at 3.01.38 PM

Learn more about CSS Shapes.

Web Speech API

Another common annoyance when combining cooking with technology is having to touch your laptop or tablet when you’re hands are messy. In order to allow you to navigate the application without touching it, we incorporated the Web Speech API. The Web Speech API allows us to receive voice commands from the user’s microphone as text. In order to make the interaction more user-friendly, we map several appropriate phrases to individual pages, which means any number of voice commands will work as the user expects. There are also some built-in commands, like “forward,” “back,” and “recipe,” that allow you to perform various functions on the site. This means you can browse through the entire application without ever touching your mouse or your screen.

Leap Motion

As we continue to demand more from our technology, it makes sense for us to create new ways of interacting with it. Multi-touch and voice input have dramatically changed the way we use our devices, and now thanks to technologies like the Leap Motion Controller, we can also use the space above and around our computers to interact with them, as well. As we were looking for ways to allow users to flip through recipes without getting ingredients all over their laptops, the Leap Motion Controller seemed like a perfect fit.

 Fortunately, Leap Motion provides an excellent javascript API that makes integrating motion control into your website extremely straightforward. If you have a Leap Motion Controller connected to your computer, you can navigate through recipe cards simply by swiping forward and back. (See the video above for a demo.)

Tooling

Most of the cutting edge features we used for the Cupcakes! demo are so new that they haven’t been tooled yet, but there is one notable exception. We wanted the site to look great at any size screen — particularly on tablets — so we’re utilizing media queries to make adjustments at various breakpoints. Designing multiple layouts for all necessary breakpoints can be difficult and tedious, but Edge Reflow simplifies the process by letting us lay out our pages and add breakpoints visually. Reflow allowed us to quickly conceptualize and communicate how elements should adapt and respond to all our target screen sizes.

Dessert

We had a fantastic time both working with Food Network, and bringing their vision of Cupcakes! to the open web. Collaborating with partners and experimenting with real-world use cases and content helps us to refine our contributions to web standards, and helps guide the development of tools to help more people bring these types of experiences to life.

If you want to experience the Cupcakes! demo for yourself, you can check it out here (Chrome and Safari only, for now). Additionally, the entire codebase is open source and available on GitHub. If you have questions or comments, feel free to leave them below.

Fragmentation of masked and clipped content – Part 2

The first part of the article “Fragmentation of masked and clipped content – Part 1” described possible scenarios how a clipping path can be broken into different fragments. The demonstrations used the CSS Multi-column layout with equally sized columns.

Fragmentation of clipping path for CSS Multi-column. The clipping path is sized as if the content was not broken into different pieces. For each fragment, the clipping path position is determined relative to the position of the current fragment in the virtually unbroken content.

Other CSS layouts like CSS Regions or CSS Overflow allow more flexibility on styling of fragment containers. A fragment container is a box that contains a fragment of the element. In a multicolumn element, each column is a fragment container.

The following example has three fragment containers. Each container has a different size and position. The content “Lorem ipsum” flows from the first container into the other two containers.

Three fragment container of different size. The content flows into each container.

Like in the first part of this article, the second part also looks at clipping path examples to help to decide how they should be influenced by fragmentation. Masking would follow the choices we make for clipping. The clipping path is the same ellipse as before with a 50% vertical and horizontal radius.

As a fragment container gets wider, less height is needed to contain the text. Since the elliptical clipping path has a vertical height of 50% the absolute clipping path height shrinks. This can have an influence on the relative offset for each fragment. The following considerations explore different sizing ideas.

The width of the paragraph changes. As wider the paragraph gets, as more shrinks the height.

The variable width of  fragment containers also extends the possibilities how to fragment a clipping path. For this reason, all examples in the second part use the first consideration of the first part of the article. It will not explore the different relative positions of the clipping path on each fragment. See the graphic in the introduction.

First Consideration

Each fragment has a different width. It is not possible to simply assume that the content was not broken anymore. More calculations need to be taken into account. Each fragment could be handled as if it contained the entire element..

The clipping path is sized for each fragment as if the content was unbroken for this fragment.

A reference size gets calculated for each fragment and it is assumed that the content is unbroken for each fragment. That means that the layout for the same content is calculated for each deviating width. This is because for each deviating width the content height differs. The resulting rectangles for the example above are (width x height):

  1. 124 x 512
  2. 182 x 338
  3. 95 x 703

The size of the clipping path for the first fragment is determined by the 124 x 512, for the second fragment by the 182 x 338 and the last fragment by the 95 x 703. The offset of each clipping path would be relative to the offset of the content of the current fragment and is also relative to the size of the current fragment. All these calculations eventually results in the graphic above.

Even if it seems that the cost are high, all the calculations need to be done anyway for proper positioning of the content.

Second Consideration

The model can still be simplified. Instead of creating an individual clipping path for each fragment if would be possible to use one reference rectangle to calculate the clipping path for all fragments.

The clipping path is sized according to the widest fragment in the fragment flow. This clipping path is then used for each fragment.

The behavior in the graphic above is currently used by WebKit. The dimension is calculated by the reference rectangle of a fragment as well – assuming that the content fills the fragment and is not broken. Instead of doing this for each fragment, the widest fragment is chosen to calculate the rectangle for all fragments.

It could be that the idea derives from CSS floats. Imagine a paragraph that is not broken into pieces. A floating element pushes the content by side. The paragraph would still not be broken into pieces. The reference rectangle would use the widest dimension of the paragraph.

Text with floating element. The reference rectangle is determined by the paragraph as a whole.

Of course there are different other possible variations that use a fixed reference rectangle for all fragments. Some examples are listed below:

Third Consideration

So far all of the examples have used an elliptical clipping path that had a relative dimension. Lets consider a circular clipping path with a radius of 62px:

clip-path: circle(62px at 62px 62px);

The following graphic fills the circular clipping path with black to demonstrate the problem:

An absolute clipping path gets repeated into the second fragment because of the smaller reference rectangle of the second fragment.

The height of the second fragment is smaller than the height of the first fragment. Even if the clipping path already covered the first fragment, it will still show up on the second fragment as well giving undesirable results.

The solution for this problem could be to sum up all absolute heights of all fragments. This sum will be the height of the reference rect.

The heights of all fragments are summed up to determine the height of the reference rectangle. The height is calculated to 370px.

The width of the reference rectangle could be with as in the first conclusion or as in the second conclusion.

A circular, absolute clipping path broken at the proper place.

Conclusion

Fragmentation gets a lot more multifaceted if the fragments do not share the same width. Finding the right solution may depend on different factors. There might not be the right solution for all of these use cases.  If you have your own solutions that should be considered as well, mail them to the www-style mailing list. Use “[css-break][css-masking]” to prefix the subject line.

Fragmentation of masked and clipped content – Part 1

Clipping and masking are graphical effects for partly or fully hiding portions of an object. A clipping path defines an area where the content will be visible. Content outside the area is invisible. An image can be used as a “mask” and the luminance of the image will determine how much of your content will be visible on the screen. Photoshop and Illustrator users are probably already familiar with clipping masks and layer masks/opacity masks. Our team is working on enabling these features in browsers with the help of CSS. The article “CSS Masking” explains CSS Masking and clipping in more detail.

The clipping path in the middle clips the image on the left side. The result can be seen on the right.

Fragmentation of content

Clipping and masking can be applied to SVG elements and HTML elements. An HTML element also has the property that it can be “broken“ into different pieces. This principle is called “fragmentation” and allows web authors to use layouts like CSS Multi-column or CSS Regions. Content that does not fit into one column or the current region is broken into different fragments and continues on the next column or region.

This article looks at clipping path examples to help decide how they should be influenced by fragmentation. Masking would follow the choices we make for clipping. To simplify the examples, the article just analyzes CSS Multi-column layout with equally sized columns. Other layout proposals like CSS Regions can create fragments of different widths and will be considered in a follow-up article.

How does a clipping path apply to content that is split into different fragments? This question is currently discussed within the CSS WG. This article demonstrates different possible solutions taking CSS Multi-column as example. In the illustration below, the clipped content is a black colored text. The text flows from the first column into the second and third column. Each column has an equal width.

An example of CSS Multi-column in use. The content flows into three columns.

An ellipse, centered on the content area, with a horizontal and vertical radius of 50% is taken as clipping path.

The elliptical clipping path.

The markup for the example could look like this:

<div>
  <h2>Lorem ipsum</h2>
  <p>Lorem ipsum dolar...</p>
</div>
<div id="content">
  <h2>Lorem ipsum</h2>
  <p>Lorem ipsum dolar...</p>
</div>
<div>
  <h2>Lorem ipsum</h2>
  <p>Lorem ipsum dolar...</p>
</div>

body {
  column-count: 3; 
}

With the clipping path applied:
#content {
  clip-path: url("#clip");
}

<svg>
<clip-path id="clip" clipPathUnits="objectBoundingBox">
  <ellipse cx=".5" cy=".5" rx=".5" ry=".5"/>
</clip-path>
</svg>

or simply:
#content {
  clip-path: ellipse();
}

The following graphics shows the clipping path applied to an element that is not fragmented:

The element on the left is not fragmented. The element on the right is the same element with a clipping path applied.

“Copy” the clipping path

A simple solution would be to “copy” the clipping path into each fragment. The clipping path would be sized and position for each fragment of the element individually, just as if each fragment is a separate element.

The elliptical clipping path is “copied” into each fragment of the element. Each fragment is responsible for positioning and sizing the clipping path individually.

Even though this seems to be a simple solution, it might not be the most desirable one. Breaking the clipping path into different fragments might be as desirable as breaking the content into different fragments.

Clipping and masking share the problem of fragmentation with the “background-image” and “border” properties. Therefore, parts of the discussion here may apply to these properties as well.

Note: The “copy” behavior may still be useful. It was suggested to let the “box-decoration-break” affect clipping and masking as well. Authors could switch between “copy” or one of the following considerations.

First consideration

In the first consideration, the browser assumes for each fragment that the content was not broken into different pieces.  The clipping path is sized according to the dimension of the “unbroken” content and positioned relative to the fragment position.

The clipping path is sized as if the content was not broken into different pieces. For each fragment, the clipping path position is determined relative to the position of the current fragment in the virtually unbroken content.

The clipping path in the first fragment is positioned at the top, in the second at the middle and in the third at the bottom.

Second consideration

The second consideration is a variation of the previous one. The clipping path is still sized as if the content was unbroken. But the position is relative to the top left of the reference box of each fragment.

The clipping path is sized as if the content was not broken. Each fragment positions the clipping path on its top left relative to the reference box.

Sizing relative to the “bounding client rect”

Another interesting solution is to compute the smallest rectangle (the “bounding client rect” named after the function getBoundingClientRect()) that includes all border boxes of each fragment and their descendants. The clipping path would be sized and positioned according to this rectangle. All fragments are clipped together as one piece by the same clipping path.

The clipping path is sized and positioned relative to the bounding client rect. The fragmented element is clipped as a “whole”.

The described behavior does not really count as fragmentation but is used by Firefox at the time of writing this article.

Conclusion

Fragmentation is an important part of the CSS layout and is documented in its own specification. The article presented different possible rendering models for clipping on fragmented content. There are more variations that can be considered.

The examples above all used the CSS Multi-column layout. CSS Multi-column has the benefit that the width of each fragment is of equal size. Other layout proposals like CSS Regions allow fragments of different widths.

Example of CSS Regions. The content flows between three regions.

How would fragments with different widths influence the sizing of clipping paths? This problem will be looked at in a follow-up article.

The CSS WG will need to decide which rendering model will be used in the future. Participate in the discussion! Sign up for the www-style mailing list and send your feedback.