The thing I'm always surprised about with these sort of CSS hacks: they don't lag my browser. Like, at all. Even the animated ones! Which is really surprising when you compare them to literally any other way these illustrations could have been created. A sufficient mess of procedural Javascript to render the same designs would lag horribly. The equivalent Flash would make the browser choppy as all hell. As would a Java applet, if those were even still around. (SVG might not, but for the SVG to animate you'd need to use... CSS.)
Is CSS effectively "free", or is this just not a complex-enough example to start to see problems?
> Is CSS effectively "free", or is this just not a complex-enough example to start to see problems?
Far from being "free" unfortunately. Especially if it is made on CPU side. But modern browsers are trying to use GPU for that. GPU has a primitive operation: render triangle with three colors at corners.
So for non-trivial gradients you will need (on CPU side) to do so called triangulation to produce meshes containing such triangles: http://www.svgopen.org/2011/papers/18-Advanced_Gradients_for....
And then you need to send that mesh to GPU for batch rendering. Quite complex machinery.
Flash and Java were trying to do all that on CPU side. But with high DPI monitors (like 300 PPI Retina - 9 times more pixels on screens) CPU rasterization is not the option anymore.
For animations that touch only primitive transformations (scale/translation/rotation/opacity), the browser will usually render the element once on CPU, upload it to the GPU as a texture, and then composite it with the rest of the page on the GPU. That makes things like the spinning BB-8 or the blinking NO VACANCY basically free on the CPU.
(I actually spoke with them personally about this while I was still at Google, but there's the design doc. It's been 2 years, so perhaps the internals have changed, but this was also the situation in WebKit at the time as well.)
And you do see weird pixelation effects - try rendering some text to a div and then animating 'transform: scale()'. You lose font antialiasing during the animation, which is why many sites that do this will fade out the text first, animate only the bounding box, and then fade the text back in.
Chrome has both the advantage and the curse of working with the rest of the web. That means they can't break existing CSS properties, and any GPU rendering needs to work with every existing website out there. The constraints they are under are much more restrictive than the constraints you are under.
There was a project to go all-GPU rendering within Chrome when I left, but it was a big project, and I don't know if they ever finished it. Even if they did, that still doesn't speak for WebKit/Edge/Firefox/Servo. (Edge is usually pretty modern when it comes to GPU acceleration, and I've heard Servo is heading this way, but Apple has historically cared very little about animation performance on WebKit, instead hoping to drive people to write native iOS apps.)
> Edge is usually pretty modern when it comes to GPU acceleration, and I've heard Servo is heading this way, but Apple has historically cared very little about animation performance on WebKit, instead hoping to drive people to write native iOS apps
This isn't really an accurate description of the current state of affairs.
Edge, Firefox, Chrome, and Safari all use essentially the same architecture for rendering. In the case of all browsers but Chrome and Firefox on non-Windows platforms, they are already doing all their rendering using vector graphics APIs that are GPU-assisted (Direct2D for Edge and Firefox; CG::OGL for Safari); at least on Windows, Chrome is the last one to catch up here. All browsers use a "paint"/"compositor" distinction, which leads to the "transform/opacity is fast, other CSS properties are slow" effect. In the case of Safari, the compositor is run by the OS window server (Core Animation); Chrome is heading this way too on Mac. For other browsers and OS's, the compositing is done by the browser itself.
This design, which essentially all shipping browsers share, is motivated not by Web compatibility concerns but rather because it was easy to retrofit onto older browser engines. Servo does things differently: it removes the distinction between painting and compositing, replacing it with WebRender, an integrated solution that handles both. This means that it can run animations off the main thread and GPU-accelerate all of them, not just transform and opacity. The legacy vector graphics APIs are cut out of the picture entirely (except for SVG/canvas), which results in a much more optimized graphics pipeline. We do not break the Web while doing so; there is nothing in the spec that requires the use of legacy vector graphics APIs when painting Web content.
You don't need to break the web to implement per-primitive transformations. Safari, FF, IE do them per-primitive for example.
The only case when transformation are made on bitmap buffers is then 3D transformations are involved. Everyone knows how to do per-primitive 2D transformations these days.
If I run it through Chrome's Timeline inspector, the majority of the time in each animation frame is spent on the GPU (0.32 ms), while Paint only takes 0.01ms and Composite Layers is 0.03ms (there're also fairly lengthy 0.13ms Recalc Styles and 0.22 Update Layer Tree phases, where I suspect it's walking the whole JSFiddle DOM to find out nothing has changed).
If I run it through Firefox's profiler, there is a lengthy Paint (~8ms), followed by only Recalc Styles per animation frame (I'm guessing that it's doing everything on the GPU and the profiler doesn't show me that work), except when the element grows enough to force a scroll bar to appear, which trigger a re-layout.
That's only true if you restrict yourself to vertex colors and shading. Every modern GPU supports fragment / pixel level shading, and can perform arbitrary gradients quite efficiently using this method.
Beautiful! Runs exceptionally smooth using Chrome on an iPad Air 2. I have no doubt the GPU is doing most of the work. Less smooth on the same device using Safari.
I suspect my iPad crashes (all the damned time) because it's running a couple dozen services that take up all the RAM. Not that the Windows phone isn't, but it seems to manage them a bit better.
For the record: No crash on an iPad mini 2 (iOS 10 beta) and an ancient old iPhone 4S (iOS 9.3.1). The picture though is not rendered perfectly but has some white lines in it.
The days of yore when hand-crafted artisinal JavaScript could demand a kings ransom is well and truly behind us. Today the linear-gradient() smiths wield their spacetime-hammers in the octarine glow of quietly exploding minds.
I could imagine it has to do with the fact that CSS is declarative and exposes a lot less "internals" to the user than JS does. This allows browsers to do a whole lot of optimisations (parallel execution, culling, delegation to GPU) without risk of breaking anything. With JS on the other hand, browsers must be careful to keep up the illusion of sequential, single-threaded execution because that's what JS code assumes.
I would compare it like this:
C is extremely fast
php which is built on C is not so fast
So css is like C, built on the internal stuff so pretty much no overhead or anything. Javascript animations are like php, built on top of css with just manipulation of the css/dom structure.
As long as we're being pedantic, it's definitely 'fewer'. 'Less' is only used in cases where you couldn't conceptually talk about a single instance of the thing being described. 'Less distance', but 'fewer miles'; 'less abstraction', but 'fewer layers of abstraction'. Even if in practice it may be difficult to find the edges of a single layer of abstraction, the word 'layers' is still metaphorically talking about a collection of individual items, and whenever this is the case we use 'fewer'.
That is not what the author of A Single Div is doing! In CSS you cannot add arbitrary vector drawings to a single div without linking to an image resource as background (SVG in that case).
What the author is doing is using the single div and its two pseudo elements before and after (so effectively the author has three elements to work with) and style the borders, border-radius, background, shadow, text-content, etc. The use of linear-gradient declarations on the background in particular is a big part of a lot of these drawings, because you can add an arbitrary number of them on any element. Look at the Tardis sample in your element inspector and toggle the background of the div; you will see that most of the door panelling and windows disappear. These are drawn with linear gradients where the colours don't blend into each other, but stop abruptly. By layering these 'gradients', you can create patterns, such as cross hatching or a grid of lines.
Edited. I usually omit he or she if I don't know the gender of the person referred to. I used he in that byline (I used the author in the main phrases) as the generic pronoun (i.e., any author of such a single-div experiment), but that may not have been clear from the context.
Only the first one is a pronoun, and it's one generally reserved for nonhumans.
I'm sure there are people out there happy to be called 'it' (or even prefer 'it' over other pronouns) but not very many. 'They' seems much more neutral to me.
Sometimes I like to look at sites like these in IE6 (through BrowserStack) -- not because I expect them to support it, of course; just because it's fascinating to see how far CSS has come. This one is particularly amusing given how rich it looks in any modern browser. http://i.imgur.com/zGycgtH.jpg
> Microsoft said that Acid3 did not agree with the goal of Internet Explorer 8 and that IE8 would improve only some of the standards being tested by Acid3. IE8 scored 20/100, which is much worse than all relevant competitors at the time of Acid3's release, and had some problems with rendering the Acid3 test page. On 18 November 2009, the Internet Explorer team posted a blog entry about the early development of Internet Explorer 9 from the PDC presentation, showing that an internal build of the browser could score 32/100.
IE and Edge never actually "passed" Acid3 either; as I recall they typically got to scores of 100 but would lag on two numbers, I want to say they were 25 and 69, whereas the test explicitly says that the animation needs to be fluid.
I got Firefox 47.0.1 to pass with 100%, but only when I reloaded the page. It failed the first time with only 99/100. Passing may require a very fast internet connection or cached data.
We had a contest at the office, the challenge was to create the most complex illustration with css and a single div, so I created http://javier.xyz/img2css/ (I have to admit that is not as fun nor interesting to create 'single divs' with img2css).
It's definitely just showing off what you can do with a single div and CSS, much like your latter examples. It's an experiment in constraints.
However, I could see something like this being useful in the case where you're using a third-party site and are only allowed to edit CSS. You probably don't need something as complicated as a cross-stitched heart, however it does show some techniques for squeezing as much in as possible.
It also could be useful for a Font-Awesome-style icon set, where you just type <i class="icon-flower"></i>, although I imagine most people would prefer to just do something like <img src="/flower.svg">.
—which would effectively treat the SVG not as an image or background or anything, but rather as a character glyph from a synthesized single-character graphical-emoji font—meaning your SVG design would be display:inline'd at the current font-size, including font-styles (oldschool faux-italics) and text-decorations (properly-positioned and shaped underline/outline drawn before the SVG glyph's stroke.)
The text engine is already incredibly expressive for doing arbitrary vector-glyph layout; so if you're creating your own one-off vector glyphs, why shouldn't you be allowed to manipulate them using the text engine?
That's an option if you want your icon monocolored, but else you'll need the other options. Or, if you want a responsive icon, you'll need the pure CSS approach AFAIK.
Right, that's the way things stand as they are today, where (afaik) only Apple's renderer actually has support for graphical emoji (and even then, it requires mipmapped bitmaps, not color vectors), and everyone else just supports emoji using what they can manage from pure OpenType specifiers.
I was more referring to a hypothetical world where text-rendering engines were slightly expanded in their purpose, becoming generalized "inline graphical glyph layout engines", and exposed an API roughly like the following:
...where the text-rendering engine would have the full capacity to render all SVG features when rendering an SVG "glyph", but would also do all the same optimizations it does to regular OpenType/TrueType glyphs (doing its own GPU-memory mipmap-generation of used ligatures at each size, etc.)
If this was done correctly, you could actually deliver a "font" as a JSON object that would be synthesized in the browser at runtime, if you wanted. (I have no idea why you'd want that, but you could. Allowing for streaming fonts where the characters used above the fold load first, maybe?) And you could generate new text-engine objects at runtime—this could be used with graphical SVG icons to achieve an effect similar to GPU texture-atlassing for games.
What is a "responsive icon"? Keep in mind that you can just switch the path to the SVG in CSS in the same way that you'd alter properties of a CSS image.
Sort of to show off, but also simply the very artsy reason of seeing what you can come up with when restricting yourself. Or to quote from the corresponding Mozilla Hacks article (link to which can be found in the page source):
But why a single div?
When I was learning to paint, my class did these color mixing exercises where we created the many colors of the spectrum from only the three primary colors: red, yellow, and blue. The purpose of the exercise is to learn the behavior of the medium and the constraints show us the power of combination. You can certainly buy green paint, but you can also create green from blue and yellow. Restricting your available options forces you to re-evaluate the tools you already have.
I decided to start a CSS drawing project, every few days illustrating something new with only CSS. To further challenge and explore what CSS is capable of, I gave myself the constraint of using only a single div in the markup. Instead of buying green paint (or adding another div), I’d need to stretch and combine CSS properties to achieve my goals.
I think there is a place for this in performance hacking for the experience around the first load of the webpage experience. You are inevitably going to load a .css file anyway, but if you include it in the .css you aren't now having to download additional assets. So in only 3 GET you could be getting your complete html, javascript and css payload, rather than 6+ of html, javascript, css and core assets. You would be spending your network budget on only the assets that make no sense to replicate via SVG but everything else would show up on time.
There's probably a case to be made as well for performance for people using electron or similar.
Yes, SVG files have come a long way and are quite useful for this type of vector graphics. However there is something so satisfying about knowing that your vector art fits into a single div and comes purely from CSS. Amazing work. These are really visually appealing to me. Soft and welcoming, yet vibrant.
Most of these do not much more than layering gradients via multiple background declarations. That gives browser developers very little room to screw up if gradients and multiple backgrounds work correctly.
It still remains a hack, of course and I guess there is little use of the technique apart from curiosity and fun.
In reality, that layering gradients via multiple backgrounds has still many quirks across current browsers: different pixel rounding errors, different blend modes often produces visually incoherent results - seams, gaps and aliasing [1].
One amusing quip: recently I have been messing with CSS3, tried the most simple use-case for `radial-gradient` I could imagine and immediately ran into Chrome bug [2] not reported at the time. I think it is somewhat illustrative.
So much good stuff here (toggling Mickey's :after border-radius is my favorite), but the title is a tad bit misleading, since the ::before and ::after pseudo-elements really act as divs.
1. Each DOM element is about 200-400 bytes (YMMV) in memory. You will need at least two of those. So to parse that SVG and build DOM structure.
2. Yet just to get that file over HTTP you will need to execute around 40,000 machine instructions. You can use data URLs to encode your SVG but that looks even more uglier.
That if to look on the problem as a whole ... But CSS is split on modules these days. Each module have their own authors that do whatever is more convenient for them. Christmas tree design, sigh.
3 is one of my biggest pet peeves with SVG. Accessing the SVG document from its container is extremely annoying and not necessarily straightforward to debug, as I learned in one of my recent side projects: http://scottmmjackson.com/weekend-project-offline-fullscreen...
I don't think that there are programs that generate CSS within this particular constraint of one div. This is more akin to code golf, where you attempt to push the boundaries of what is possible within a strict set of limits.
It looks like use them for CSS properties. The background for the outer div is set to #4e6590, the blue background. The background-image of the inner div (and its ::before and ::after) draw the parts of the zipper.
For example, the inner div has background-image of
From looking at the code, the empty div is the single div used for the image. The parent div is just the seperator for presentation - the coloured background. Otherwise they'll need a page per demo
Is CSS effectively "free", or is this just not a complex-enough example to start to see problems?