Adobe

decor

Web Platform Team Blog

Making the web awesome

Blending HTML elements in Safari and Firefox

In June 2014 at the Worldwide Developer Conference, Apple announced that Safari 8 would ship with support for CSS Blending. With the recent release of iOS 8, you can now use blend modes on your Apple mobile devices! OS X Mavericks users who update Safari to version 7.1 can also start experimenting with this new feature. And this is not the only good news: Firefox recently enabled the mix-blend-mode CSS property by default in version 32, released on September 2, 2014.

wp-blendmodes

Safari and Firefox are the first browsers to ship the CSS Blending feature! These implementations are based on the CSS Blending specification – which has reached W3C Candidate Recommendation status. There are a few remaining work items to be completed in these two browsers: the non-separable blend modes in Safari and the CSS isolation property in Firefox.

Chromium also has a complete implementation of the CSS Blending specification: the background-blend-mode property is supported by default, while mix-blend-mode and the CSS isolation property are available behind the experimental features runtime flag. You can play with the full implementation of blend modes in Chromium-based browsers (Chrome and Opera) by enabling this flag.

Want to know more about CSS Blending? The Adobe Web Platform Team’s website contains additional information about this feature, along with a list of useful resources that will allow you to create compelling visual effects using blend modes.

Please share your thoughts and experiences regarding CSS Blending in the comments here, or on Twitter.

Happy Blending!

Safari and Opera join Chrome in shipping CSS Shapes

The last few weeks have been exciting for CSS Shapes. At the end of August, Shapes shipped in Chrome 37. Then in early September, Opera 24 also shipped with support for Shapes. And now, iOS 8 just launched with Shapes support in Safari! Also, support for OS X versions of Safari will be coming soon.

What is CSS Shapes?

CSS Shapes allows you to build layouts like this on the web. In this example, the text content wraps around the contour of the hanging-lamp and the wall (photo and demo by @ZoltanWebkit). The contour of the shape is defined by a polygon with the help of the CSS Shapes Editor. (Note that this example uses the CSS Shapes Polyfill, so it works in all browsers.)

See the Pen Hanging-Lamp, with polyfill by Adobe Web Platform (@adobe) on CodePen.

If you’re not familiar with CSS Shapes, you should definitely take a look at Shapes 101 article. More information and useful links can also be found on the CSS Shapes page.

But can I really use it now?

Yes! Even though Firefox and Internet Explorer don’t support CSS Shapes yet, you can use them today in production. In browsers that don’t support Shapes, you simply get the standard float wrapping behavior. For example, view the following demo in a browser that supports shapes and one that does not.

See the Pen Monsters, without polyfill by Adobe Web Platform (@adobe) on CodePen.

For cases where having the shape is essential, you can use the CSS Shapes Polyfill, which supports many of the use cases for CSS Shapes. The polyfill is smart enough to use the built-in Shapes functionality in your browser if that is available. For example, here is the previous demo with the polyfill enabled, so it will look great in browsers that support shapes and browsers that don’t. Most notably, if you compare the source of the two demos, you will notice that nothing needs to change but to include the JavsScript for the polyfill.

See the Pen Monsters, with polyfill by Adobe Web Platform (@adobe) on CodePen.

If you’re doing something more exotic, like emulating shape-inside, then you can use Modernizr — or when they are more widely supported, Feature Queries — to remove or modify the floats when CSS Shapes support isn’t present. The following example does just that.

See the Pen Emulating Shape Inside with Shape Outside, with Modernizr fallback by Adobe Web Platform (@adobe) on CodePen.

Make something cool

We hope you’re as excited about the availability of CSS Shapes as we are. Go out and play with it, and build great things! We’d love to hear about your experiences and the things you build in the comments here, or drop us a line on Twitter @AdobeWeb!

Announcing webplatform.adobe.com

Today we’re proud to announce the launch of a new team website: webplatform.adobe.com.

The site provides a new view into the team’s wide range of projects. We lay out a welcome mat to draw visitors into each project, then lead them to more detailed information, like what we share in blog posts.

Our mission is to create a more expressive web. With this new site, we want to connect new forms of expression with their enabling technology in a way that speaks to all web creatives. By putting design use cases front and center, we hope to feed a discussion that includes designers, developers, standards gurus, browser implementors and casual creators of apps and websites.

Like teams everywhere, we do a lot of research and project work that mutates into something totally different, or gets abandoned for other, more valuable, efforts. These are valuable lessons, which we will increasingly share on both the website and this blog. Feedback on what we’re not doing can be just as valuable as feedback on what we are doing!

Thanks for joining us on this next experiment. We’re excited to hear your responses and suggestions. Post your thoughts on the new website in the comments below or on Twitter: @adobeweb.

Event: Evolving the Design Palette for the Web, 9/18

At the heart of it, the Adobe Web Platform team is an engineering organization. We address problems designers have when they bring their ideas to the web. We’re keenly interested in areas where designers have had to compromise their ideas due to limitations of the web platform. This informs the new work we take on and existing work we’re doing.

Next week, we’re hosting a special event to engage designers, begin to understand their design limitations and start the process of working together to solve them. We’re pleased to have a guest speaker Michael Janiak, Creative Director at Fluid. Following Michael’s talk will be drinks, a DJ, and casual conversations about evolving the web together.

If you’re a designer and will be in San Francisco, please join us on September 18 at the 111 Minna Gallery. Space is limited, so register now: http://evolvingtheweb.eventbrite.com.

CSS Shapes Editor for Chrome

With the release of Chrome 37, CSS Shapes are enabled by default for everyone to use.

To make it easier for you to work with the new feature, there is now a CSS Shapes Editor for Chrome. This Developer Tools extension adds an interactive editor for shapes right in the browser. Learn more about it and watch a quick video demo of the editor in action on my blog post.

edit polygon shape

Editing a polygon path using the CSS Shapes Editor for Chrome

Standalone CSS Shapes Editor

The Chrome extension uses the same editing surface as the CSS Shapes Editor extension for Brackets. We think that’s practical and useful, so yesterday we also released the editing surface as a standalone CSS Shapes Editor on GitHub. As a developer, you can now integrate the shapes editor into your own tools, demos and interactive presentations.

CSS Shapes now available in Chrome 37 release

Support for CSS Shapes is now available in the latest Google Chrome 37 release.

chromelogo

What can I do with CSS Shapes?

CSS Shapes lets you think out of the box! It gives you the ability to wrap content outside any shape. Shapes can be defined by geometric shapes, images, and even gradients. Using Shapes as part of your website design takes a visitor’s visual and reading experience to the next level. If you want to start with some tutorials, please go visit Sarah Soueidan’s article about Shapes.

Demo

The following shapes use case is from the Good Looking Shapes Gallery blog post.

Without CSS Shapes
the_11_guesses_no_shapes
With CSS Shapes
the_11_guesses_shapes

In the first picture, we don’t use CSS Shapes. The text wraps around the rectangular image container, which leads to a lot of empty space between the text and the visible part of the image.

In the second picture, we use CSS Shapes. You can see the wrapping behavior around the image. In this case the white parts of the image are transparent, thus the browser can automatically wrap the content around the visible part, which leads to this nice and clean, visually more appealing wrapping behavior.

How do I get CSS Shapes?

Just update your Chrome browser to the latest version from the Chrome/About Google Chrome menu, or download the latest stable version from https://www.google.com/chrome/browser/.

I’d like to thank the collaboration of WebKit and Blink engineers, and everyone else in the community who has contributed to this feature. The fact that Shapes is shipping in two production browsers — Chrome 37 now and Safari 8 later this year — is the upshot of the open source collaboration between the people who believe in a better, more expressive web. Although Shapes will be available in these browsers, you’ll need another solution for the other browsers. The CSS Shapes Polyfill is one method of achieving consistent behavior across browsers.

Where should I start?

For more info about CSS Shapes, please check out the following links:

Let us know your thoughts or if you have nice demos, here or on Twitter: @AdobeWeb and @ZoltanWebKit.

iframeflow.js

The CSS Regions specification is currently supported by Internet Explorer 10+ and Safari (OSX and iOS). Though generally very close, the IE implementation was based on an earlier draft and works differently. In particular, the source of a named flow – the elements you apply the -ms-flow-into property to – must be iframe elements. This approach has some benefits: it allows the use of content from any source, including cross-domain content, with all the security benefits of an iframe. The standard specification, however, chose to limit named flow content to the current document using any element type.

This makes using CSS Regions in both environments slightly challenging. Since the WebKit implementation is easier to use – no iframes needed – and reflects more recent spec drafts, we attempted to write a JavaScript library that would let a region chain authored for Safari work in IE. The result is iframeflow.js.

How It Works

iframeflow simply generates the iframe required by IE and copies named flow content to the iframe document. It can either do so automatically by scanning the page’s stylesheets for named flows; or it can create an IE named flow from an arbitrary selector.

Caveats

Of course, this library only helps in IE. To emulate CSS Regions across browsers, you should use the CSS Regions polyfill. But if your iOS app uses Regions in a WebView, iframeflow.js could help you produce a Windows 8 app with the same content.

Other known limitations include cross-domain stylesheets (their object model is off-limits). If the style of elements in your named flow depends on their ancestry – e.g. because they match child or descendant selectors – this styling may no longer apply in the iframe document. Other constraints are listed on the project page.

Tinkering

The source code is available on GitHub. Please let us know if you have any feedback. You can do so through GitHub issues, on this blog, or via twitter @adobeweb.

Coming Soon: CSS Feature Queries

Feature Queries are part of the CSS3 Conditional Rules specification, and offer a native method of testing for CSS feature support. You can use Feature Queries to test whether certain CSS rules are supported, and optimize your page for the available set of features. Feature Queries have a number of stable browser implementations in Chrome, Firefox, and Opera, and at least one recent experimental implementation in WebKit. As browser support continues to increase, it’s probably worth taking a look to see if Feature Queries fit into your current projects.

Feature Queries in CSS

Feature Queries look like Media Queries, but test support for CSS property/value pairs rather than display characteristics. As a basic example, you could ask a browser to apply a set of CSS rules if it supports a value of 0 for the margin property.

@supports (margin: 0) { /*CSS to apply*/ }

Let’s move on to a more realistic example. Let’s say you want to use background-blend-mode to colorize a background image, multiplying a color tint over the original grayscale image.

See the Pen Feature Queries + Blend Modes by Adobe Web Platform (@adobe) on CodePen.

body {
  background-blend-mode: multiply;
  background: linear-gradient(rgb(59, 89, 106)
                , rgb(63, 154, 130))
              , url(background.png);
}

Altogether a great effect, right? However, browser support is a bit of a pain. background-blend-mode has relatively wide support, but there are also a good number of browsers where you will not see the correct result. To address non-supporting browsers, we will lay down a base set of functionality – an approximation using a semi-transparent color overlay.

body {
  background: #3F9A82;
  background: linear-gradient(rgba(59, 89, 106, 0.8)
                , rgba(63, 154, 130, 0.8))
              , url(background.png);
}

The above code includes a single-color fallback if the semi-transparent color overlay isn’t supported. Then, using a feature query, we can conditionally update the background if background-blend-mode is supported. A feature query looks just like a media query, using @supports and adding the CSS declaration to be tested inside parentheses.

@supports (background-blend-mode: multiply) {
  body {
    background-blend-mode: multiply;
    background: linear-gradient(rgb(59, 89, 106)
                  , rgb(63, 154, 130))
                , url(background.png);
  }
}

Feature Queries in JavaScript

The Feature Queries specification also provides a JavaScript interface: CSS.supports. We can take the above example, and test for support using JavaScript. If background-blend-mode: multiply is supported, we can add the blend-mode class to the <body> element.

See the Pen Feature Queries + Blend Modes (JS) by Adobe Web Platform (@adobe) on CodePen.

window.onload = function() {
  if (CSS.supports('(background-blend-mode: multiply)'))
    document.body.classList.add('blend-mode');
}
body.blend-mode {
  background-blend-mode: multiply;
  background: linear-gradient(rgb(59, 89, 106)
                , rgb(63, 154, 130))
              , url(background.png);
}

As one further trick, you can also combine tests using logical operators and, or, and not. For example, if you wanted to test that the background-blend-mode and background property values were both supported, you could use either of the following:

@supports (background-blend-mode: multiply)
          and (background: linear-gradient(...), url(...))

or

CSS.supports('(background-blend-mode: multiply) \
              and (background: linear-gradient(...), url(...))');

Feature Queries are almost ready for primetime development. When considering whether to use them, just make sure that they are available in the same browsers as the features you are testing for. Although Feature Queries won’t make the headache of feature testing go away, they will hopefully make the problem a bit more manageable. Try it out, and let us know what you think.

One Weird Trick to Baseline-Align Text

I’m writing this post because I hope I’m wrong. I have found a silly solution to a common typographic problem, and I hope there’s a better way to do what I want.

The problem is baseline-aligning text. I want to position a character’s baseline at a particular spot, in a way that works with all browsers, fonts and font sizes. The reason I want to do this is for drop cap positioning. A drop cap should have its baseline aligned with the lowest line of regular text it’s next to. I can estimate where that baseline is, so the trick is figuring out how to get the drop cap’s baseline to match.

Let’s simplify the problem. Say I have a 100x100px div with a border. The div contains a span with a single letter, and I want the baseline of that letter to sit on the bottom edge of the border.

<div>
  <span>T</span>
<div>
div {
  width: 100px;
  height: 100px;
  border: thin black solid;
}
span {
  font-size: 100px;
  line-height: 100px;
  background-color: #9BBCE3;
}

I’ve started with a font-size and line-height of 100px. This won’t do what I want, because in CSS line-height is measured from the ascender to the descender. You might think (as I initially did) that all I’ll need to do is find the descender height and use a margin to make the text sit down on the border. The descender height will vary from font to font, so whatever solution might have to be font-specific.

But I quickly found that not only is the baseline position dependent on the font, it also varies by browser. Here’s the result of the above in Firefox, Chrome and IE:

Default letter 'T' rendered in Firefox, Chrome and IE

Firefox, Chrome and IE rendering

Firefox and Chrome are both on MacOS using the same font, but the baseline is much higher in Firefox than Chrome. IE is using a different font file for the default font, but manages to match Chrome in this instance. At this point I thought there might be a bug in Firefox, or that I might just need to conjure a Firefox-specific offset to get cross-browser baseline alignment.

But it’s not as simple as that. The variations in browser baseline positioning are compounded by font changes. Here’s the result with font-family set to Adobe Garamond Pro (the same font file used in each browser):

Garamond letter 'T' rendered in Firefox, Chrome and IE

Firefox, Chrome and IE rendering

Here Firefox and Chrome are merely one pixel apart, and IE has decided to go its own way. I tried a few other fonts and found a mishmash of results – the browsers do not agree on where to place text baselines, and have no pattern across fonts that I could discern. Dealing with descender height in order to place a baseline at a particular point appears both font-specific and browser-specific in a way I couldn’t untangle.

By the way, I originally added the background-color to the span to see if that would illuminate why the results were so different. But as you can see that’s another cross-browser inconsistency. Chrome isn’t even consistent with itself on the extent of a span’s background when I change the font. This is a separate issue, and not terribly relevant to the baseline alignment problem.

So, what to try next? I know from past experience that inline images use the bottom edge of the image as the baseline. Perhaps there’s something useful about replaced elements or inline blocks that I can exploit. It turns out that if I add an empty inline-block strut to the div, I can use it to position the baseline for the entire line.

<div>
  <span class="letter">T</span>
  <span class="strut"></span>
<div>
div {
  width: 100px;
  height: 100px;
  border: thin black solid;
}
.letter {
  font-size: 100px;
  line-height: 0px;
  background-color: #9BBCE3;
}
.strut {
  display: inline-block;
  height: 100px;
}

The baseline of the strut is placed at its bottom margin edge, which is determined solely by the height of the strut in this case. And if the letter span’s line-height is smaller than the strut’s height, the letter’s baseline will move to match. Here I’ve set the line-height of the letter’s span to 0px to make sure it’s smaller. You can check out the result in any browser in this pen (try changing the font and/or the font-size):

The strut has to be empty. At first I had no idea why, but my colleague @sgalineau found the reference in the very last sentence of the CSS 2.1 section on line height. There’s a special case for an inline-block with no line boxes that gives us this useful result.

As I mentioned, my specific reason for all of this was drop cap positioning, but there are plenty of other reasons to want to align a text baseline to something else. Is this inline-block strut trick the best we have to work with in CSS? Can someone show me a better way? If so, leave a comment here or contact me at @adobeweb and/or @alanstearns.

CSS Regions and Selectors

Selectors

The CSS Selectors system is the driving force behind the stylesheets of a Web page. The selector of a rule defines what elements or pseudo-elements get to be styled using that rule. The selectors language has advanced a lot lately and it allows a lot of complex constructs using tag names, ids, classes, pseudo-classes and so on.

An important part of the language are the combinators which define relations between two selectors. The Editors Draft of CSS Selectors Level 3 lists four combinators:

  • the descendant combinator (E F)
  • the child combinator (E > F)
  • the following-sibling combinator (E ~ F)
  • the next-sibling combinator (E + F)

There’s a general forward direction in the DOM tree when combining selectors. There is no “parent” or “ancestor” combinator. However, the CSS Selectors Level 4 draft defines the :has pseudo-class that’s supposed to fill in that role. The major limitation of this pseudo-class is that browsers are not supposed to implement it for dynamic selectors, just for cases that don’t impact performance too much, such as the Document.querySelector function.

To understand why :has is a problem if used for rule definitions let’s see how browsers actually do selectors matching. A browser doesn’t start with the rule and try to determine what elements must use that rule. It’s the other way around. The browser knows the element it needs to style and then it evaluates each selector from right to left, eliminating rules that don’t match. In the case of a combinator, once the right side was validated using the element, the browser then recursively verifies if the left side can be matched against the corresponding elements for that type of combinator. For example, the child combinator will use the parent of the element and the following-sibling combinator will verify all the previous siblings of the element to find a match. If all the selectors in the combinator match, the rule is used for the element.

This algorithm is efficient because most of the rules are usually eliminated in the early stages of the matching process. Also, when styling an element, only the ancestors and the previous siblings of the element matter. The :has pseudo-class complicates these rules. The elements matched by :has need to track all the changes in their DOM subtree that can enable or disable the rule. When misused, the :has pseudo-class can easily lead to document wide style invalidation and major performance degradations.

Regions

How CSS Regions can help in this situation? One of the interesting properties of CSS Regions is that content collected in a named flow can be rendered in regions located anywhere inside the document as long as cycles are avoided. This means that you can write stuff like this:

<div class="content"></div>
<div class="region"></div>

<style>
.content {
    flow-into: flow;
}
.region {
    flow-from: flow;
}
</style>

This code will display the content element inside the region element. In this situation, a rule with a .content + .region selector will actually behave like a parent selector. It will style the box containing the content.

I think this is especially powerful when dealing with interactivity. For example, the :hover pseudo-class is constrained by the selector rules. You can’t hover an element on a page and apply an effect to another element unrelated (not a child or sibling) to the first one. With regions this limitation can be avoided:

  1. Place the element to be hovered (A) as a previous sibling of the element you want to be styled (B).
  2. Add a region in the page and flow B inside it.
  3. Write a next sibling combinator rule between them A:hover + B and B will be styled even though it’s not rendered as a sibling of A any more.

Here is an example that better demonstrates the feature in Safari 7+:

Check out this Pen!

You can also add both elements to a flow thread and use forced breaks to split them in two different regions. This technique is used in the following example that works in Internet Explorer 10+:

Check out this Pen!

Conclusions

Feel free to experiment with this idea and bring new ones to the table. We’re always looking for ways to improve the Web Platform and empowering users to achieve the effects they want is a priority.