A Single Div
a.singlediv.com
a.singlediv.com
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.
https://www.chromium.org/developers/design-documents/gpu-acc...
(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.
Here is what happens in my Sciter: http://sciter.com/screenshots/css-transform.png
As you see the rendering is made in vector form, not as a bitmap rotation.
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.)
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.
https://jsfiddle.net/nqaoq52n/3/
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.
No browser does this.
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.
What a time to be alive.
http://www.keithclark.co.uk/labs/css-fps/nojs/
Edit: The site seems to be overloaded. Here's an archive:
https://web.archive.org/web/20160702222211/http://keithclark...
For me, it doesn't run well on FF, but neatly in Chrome. Huge difference.
That would depend on your browser. Because AFAIK there is nothing in the CSS spec that guarantees any minimum performance.
So don't count on it being fast!
Not strictly true; it's also possible to animate SVGs using ECMAScript or SMIL: https://www.w3.org/TR/SVG/animate.html
The difference is SVG + CSS is a better abstraction for creating illustrations than crazy CSS gradient and box shadow hacks.
Probably the easiest way to do this automatically is through adobe illustrator. You can convert an arbitrary file to CSS:
https://helpx.adobe.com/illustrator/using/css-extraction.htm...
I guess a lot of people think it's neat in a 'web-hack' sort of way, but it's just another way to express the same thing.
Pay no attention to the man behind the curtain.
That explains quite a lot.
CSS hacks just got a lot less impressive for me.
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.
Some of these are actually really clever.
"that thing"
"the human"
"this being"
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.
Ah, memories. https://en.wikipedia.org/wiki/Acid3
Or is it mostly to show off in the same spirit as obfuscated C contests or demo scenes?
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">.
.icon-flower:before {
content: url(/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?
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:
Text.compileGlyph(Buffer) -> Text.Font.Glyph
Text.Font() -> Text.Font
Text.Font.mapLigature([Text.Codepoint], Text.Font.Glyph) -> ()
Text.Font.getUniqueName() -> String
Then the above CSS would be a shortcut for doing this Javascript: function createImageIconClass(className, someSVGURL) {
const svg_glyph = Text.compileGlyph(someSVGURL)
const synthesized_font = new Text.Font()
synthesized_font.mapLigature(Text.Codepoint.fromString("\uE075"), svg_glyph)
const font_name = synthesized_font.getUniqueName()
const synthesized_css = document.createElement('style')
synthesized_css.type = 'text/css'
synthesized_css.innerHTML = `
.${className}:before {
font-family: ${font_name};
content: "\E075";
}
`
document.getElementsByTagName('head')[0].appendChild(synthesized_css)
}
...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.
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.There's probably a case to be made as well for performance for people using electron or similar.
https://github.com/ManrajGrover/SingleDivProject
(I have contributed a handful myself)
It still remains a hack, of course and I guess there is little use of the technique apart from curiosity and fun.
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.
[1] Look for example at http://codepen.io/myf/pen/Bzmmry in Chrome and Firefox. [2] https://bugs.chromium.org/p/chromium/issues/detail?id=623714
https://www.w3.org/TR/selectors/#pseudo-elements:
> Note: A future version of this specification may allow multiple pseudo-elements per selector.
Oh, please, please, please!
With them, without any hacks like those you can define arbitrary shapes in CSS and in <img src="...">:
div {
background-image: url(path:c 50,0 50,100 100,100 c 50,0 50,-100 100,-100);
background-repeat: no-repeat;
}
Symbols on the right of path: are the same that appear in SVGs path d attribute: <path d="c 50,0 50,100 100,100 c 50,0 50,-100 100,-100" fill="#000" />
But in significantly more lightweight manner.Proposal did not go through. Nobody cares, sigh. So people keep hacking gradients with CSS.
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.
3. With such path images you can write:
button { background-image: url(path: ...);
fill: blue; }
button:hover {
fill: red; }
With SVG you cannot do that - each SVG is a standalone document. So you will need two such images, see #1 and #2 above.4. And one more: CSS needs the way to define arbitrary shapes : https://www.w3.org/TR/css-shapes-1/#supported-basic-shapes . Ugly and far from complete set. Why not proven construct that we already have WYSIWYG tools for editing?
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.
More information is available here:
<div id="zipper" class="entry">
<div></div>
</div>
why is this a thing? what is with empty div? is it necessary?For example, the inner div has background-image of
linear-gradient(to top, transparent 10px, #aaa 10px, #aaa 15px, #ccc 15px, #ccc 30px, transparent 30px), repeating-linear-gradient(to bottom, transparent, transparent 5px, #ddd 5px, #ddd 10px), repeating-linear-gradient(to bottom, #ccc, #ccc 5px, transparent 5px, transparent 10px);
which draws the teeth of the zipper.May help you too!