Post pobrano z: Subform![]()
Archiwum kategorii: CSS
Creating Non-Rectangular Headers
Post pobrano z: Creating Non-Rectangular Headers
Over at Medium, Jon Moore recently identified „non-rectangular headers” as a tiny trend. A la: it’s not crazy popular yet, but just you wait, kiddo.
We’re talking about headers (or, more generally, any container element) that have a non-rectangular shape.
Such as trapezoids:

Or more complex geometric shapes:


Or rounded/elliptical:

Or even butt-cheek shaped:

My money is on these gaining popularity too. So let’s beat the crowd, and talk about a few ways of coding these up. Because let’s face it: they do look pretty awesome.
Image
Perhaps the simplest way to create any of the non-rectangular headers pictured above is to slap an image on top of your header.
See the Pen Image file-based non-rectangular header by Erik Kennedy (@erikdkennedy) on CodePen.
But there are a few issues here:
- Responsive behavior? These masks tend to be full-width, and it becomes tedious to define multiple widths of the shape (e.g. srcset) or risk pixelation of raster assets.
- It’s a totally separate file that needs to be fetched from the server – seems wasteful for simple shapes.
- It’s slow to iterate in-browser if you have to re-export an image file(s) from your design program.
We can solve all of these problems at once. You might already know where this one is going.
SVG
Compared to exporting a JPG from Sketch, using an inline SVG is more performant, easy to make responsive, and easy to iterate the design of. In fact, for most cases, this is the way I’d recommend using. Versatile, cross-browser, vector, and fabulous.
See the Pen SVG trapezoidal header by Erik Kennedy (@erikdkennedy) on CodePen.
With an angled background one like, one choice you have to make is: what should remain constant as the screen-width changes, the angle or the height differential between the two sides?
If you want the angle to remain constant, set the height of the SVG in vw:

If you want the height differential to remain constant, set the height of the SVG in pixels:

And you need not pick just one – we can style this responsively, since SVG elements are subject to media queries. Check out this geometric style header at widths below and above 700px.
See the Pen Responsive SVG header by Erik Kennedy (@erikdkennedy) on CodePen.
Shoot, son. What’s not to love? Oh, and we can even do the butt-cheeks style.
See the Pen SVG „butt-cheeks” header by Erik Kennedy (@erikdkennedy) on CodePen.
(Perhaps that’s more properly done with beziers, but you get the idea!)
One more thing worth nothing, and that is if you want to do an SVG background entirely in CSS, you could save the SVG and reference its URL in a pseudo element.
header::after {
content: "";
position: absolute;
bottom: 0;
width: 100%;
height: 100px;
background: url(divider.svg);
}
And if you use `divider.svg` as a repeating element in different scenarios, you can also color it different as you need:
header::after polygon {
fill: white;
}
But here’s an issue: what if the section below the header has a complicated background? In all these examples so far, we’ve just assumed a plain white background. What if there’s a fancy gradient, or another background image or something? Then what?
clip-path
This property comes to the rescue if you have a moderately complex background below the header, and therefore want the masking to be done from within the non-rectangular header, as opposed to by an element after it.
See the Pen Non-Rectangular Header Using Clip-Path by Erik Kennedy (@erikdkennedy) on CodePen.
And like the similar SVG syntax, if you want to change the responsive behavior of the above from angle-is-held-constant to height-differential-is-held-constant, you can change the calculated height to a simple percentage.
Clip-path’s biggest downside? Browser support is not that great. However, depending on how important your non-rectangular header or div is, it might qualify as a progressive enhancement. In which case, clip-path away!
border-radius
Now, up to now, we’ve only mentioned methods that work for generating all the shapes I called out above. However, if we know what particular shape we want our header to have, we might have access to an easier way.
For instance, a convex elliptical header is a perfect fit for border-radius.
See the Pen Convex elliptical header by Erik Kennedy (@erikdkennedy) on CodePen.
And a concave elliptical header could simply have the border-radius on the element after the header.
section {
border-bottom-left-radius: 50% 20%;
border-bottom-right-radius: 50% 20%;
}
Another benefit to this method is that the background of the section below the header could still have background images.
transform: skew
If we know that we want to create do a trapezoidal header, we can use a CSS transform to skew the whole thing.
See the Pen Trapezoid Header Using Transform: SkewY by Erik Kennedy (@erikdkennedy) on CodePen.
This has the side effect of skewing any child elements of the skewed element, so you’ll want to add a child element in the header that gets skewed, and everything else will go in sibling elements.


Stripe’s homepage design uses this method, and even more brilliantly, they include a few children spans (each is a block of color) that get skewed with the parent element, creating a more complex and colorful effect.
Which is best?
As far as I’m concerned, SVG is generally the way to go. However, if you have a more complex background below the header, then the best choice depends on the shape. In that case, I’d investigate if skew or border-radius could meet the art direction needed, or if browser support was enough of a non-issue to go with clip-path.
| Allows complex BG below | Browser support | Shapes creatable | |
|---|---|---|---|
| Image | No | Yes | All |
| SVG | No | Yes | All |
| Clip-path | Yes | No | All |
| Border-radius | Yes | Yes | Elliptical only |
| Transform: skew | Yes | Yes | Trapezoidal only |
Erik Kennedy is an independent UX/UI designer and the creator of Learn UI Design, a practical online video course about visual design for screens. Includes color, typography, process, and more. Over 16 hours of video across 30+ lessons.
Creating Non-Rectangular Headers is a post from CSS-Tricks
Most of the web really sucks if you have a slow connection
Post pobrano z: Most of the web really sucks if you have a slow connection
Dan Luu on the sorry state of web performance:
…it’s not just nerds like me who care about web performance. In the U.S., AOL alone had over 2 million dialup users in 2015. Outside of the U.S., there are even more people with slow connections.
This other note is also interesting, and I think that Dan is talking about Youtube’s project “Feather” here:
When I was at Google, someone told me a story about a time that “they” completed a big optimization push only to find that measured page load times increased. When they dug into the data, they found that the reason load times had increased was that they got a lot more traffic from Africa after doing the optimizations. The team’s product went from being unusable for people with slow connections to usable, which caused so many users with slow connections to start using the product that load times actually increased.
Direct Link to Article — Permalink
Most of the web really sucks if you have a slow connection is a post from CSS-Tricks
What Really Makes a Static Site Generator?
Post pobrano z: What Really Makes a Static Site Generator?
I talk a lot about static site generators, but always about using static site generators. In most cases, it may seem like a black box. I create a template and some Markdown and out comes a fully formed HTML page. Magic!
But what exactly is a static site generator? What goes on inside that black box? What kind of voodoo is this?
In this post, I want to explore all of the parts that make up a static site generator. First, we’ll discuss these in a general fashion, but then we’ll take a closer look at some actual code by delving deep inside HarpJS. So, put your adventurer’s cap on and let’s start exploring.
Why Harp? For two reasons. The first is that HarpJS is, by design, a very simple static site generator. It doesn’t have a lot of the features that might cause us to get lost exploring a more comprehensively full-featured static site generator (like Jekyll for instance). The second, much more practical, reason is that I know JavaScript and don’t know Ruby very well.
The Basics of a Static Site Generator
The truth is, a static site generator is a pretty simple concept. The key ingredients to a static site generator are typically:
- A template language(s) for creating page/post templates
- A lightweight markup language (typically Markdown) for authoring content
- A structure and markup (often YAML) for providing configuration and metadata (e.g. „front matter„)
- A set of rules or structure for organizing and naming files that are exported/compiled, files that are not and how these files will be handled (e.g. frequently prefacing a file or folder with an underscore means that it is not exported into the final site files or all posts go in a posts folder)
- A means of compiling templates and markup into HTML (frequently support for CSS or JavaScript preprocessors is also included)
- A local server for testing.
That’s it. If you’re thinking, „Hey… I could build that!” you are probably correct. Things start to get complicated though when you start to expand the functionality, as most static site generators do.
So, let’s look at how Harp handles this.
Getting to the Harp of the Matter
Let’s look at the basics of how Harp handles the key ingredients described above. Harp offers more than this handful of functionality, but, for the sake of our examination, we’ll stick to those items.
First, let’s discuss the basics of Harp.
Harp Basics
Harp supports Jade and EJS (for templating) and Markdown as its lightweight markup language (for content). Note that while Jade is now called Pug, Harp has not officially transitioned in their documentation or code, so we’ll stick with Jade here. Harp also offers support for other preprocessing such as Less, Sass, and Stylus for CSS and CoffeeScript for JavaScript.
By default Harp does not require much in the way of configuration or metadata. It tends to favor convention over configuration. However, it allows for specific metadata and configuration using JSON. It differs from many other static site generators in that file metadata is contained outside of the actual file within a `_data.json` file.
While it is configurable to a degree, Harp has certain established guidelines for how to structure files. For example, in a typical application, the files that are served fall within a public directory. Also, any file or folder prefaced by an underscore will not be served.
Lastly, Harp offers a basic local web server for testing that includes some configurable options. And, of course, it will compile the finished HTML, CSS and JavaScript files for deployment.
Let’s Look at Harp’s Actual Source Code
Since much of what makes a static site generator are rules and conventions, the code centers around the actual serving and compiling (for the most part). Let’s dig in.
The Server Function
In Harp, serving your project is usually done by executing harp server from the command line. Let’s look at the code for that function:
exports.server = function(dirPath, options, callback){
var app = connect()
app.use(middleware.regProjectFinder(dirPath))
app.use(middleware.setup)
app.use(middleware.basicAuth)
app.use(middleware.underscore)
app.use(middleware.mwl)
app.use(middleware.static)
app.use(middleware.poly)
app.use(middleware.process)
app.use(middleware.fallback)
return app.listen(options.port || 9966, options.ip, function(){
app.projectPath = dirPath
callback.apply(app, arguments)
})
}
While the function looks simple, obviously there is a ton going on within middleware that isn’t illustrated here.
The rest of this function opens up a server with the options you specify (if any). Those options include a port, an IP to bind to and a directory. By default the port is 9000 (not 9966 as you might guess by the code), the directory is the current one (i.e. the one Harp is running in) and the IP is 0.0.0.0.
The Compiler Function
Staying within index.js, let’s take a look at the compile function next.
exports.compile = function(projectPath, outputPath, callback){
/**
* Both projectPath and outputPath are optional
*/
if(!callback){
callback = outputPath
outputPath = "www"
}
if(!outputPath){
outputPath = "www"
}
/**
* Setup all the paths and collect all the data
*/
try{
outputPath = path.resolve(projectPath, outputPath)
var setup = helpers.setup(projectPath, "production")
var terra = terraform.root(setup.publicPath, setup.config.globals)
}catch(err){
return callback(err)
}
/**
* Protect the user (as much as possible) from compiling up the tree
* resulting in the project deleting its own source code.
*/
if(!helpers.willAllow(projectPath, outputPath)){
return callback({
type: "Invalid Output Path",
message: "Output path cannot be greater then one level up from project path and must be in directory starting with `_` (underscore).",
projectPath: projectPath,
outputPath: outputPath
})
}
/**
* Compile and save file
*/
var compileFile = function(file, done){
process.nextTick(function () {
terra.render(file, function(error, body){
if(error){
done(error)
}else{
if(body){
var dest = path.resolve(outputPath, terraform.helpers.outputPath(file))
fs.mkdirp(path.dirname(dest), function(err){
fs.writeFile(dest, body, done)
})
}else{
done()
}
}
})
})
}
/**
* Copy File
*
* TODO: reference ignore extensions from a terraform helper.
*/
var copyFile = function(file, done){
var ext = path.extname(file)
if(!terraform.helpers.shouldIgnore(file) && [".jade", ".ejs", ".md", ".styl", ".less", ".scss", ".sass", ".coffee"].indexOf(ext) === -1){
var localPath = path.resolve(outputPath, file)
fs.mkdirp(path.dirname(localPath), function(err){
fs.copy(path.resolve(setup.publicPath, file), localPath, done)
})
}else{
done()
}
}
/**
* Scan dir, Compile Less and Jade, Copy the others
*/
helpers.prime(outputPath, { ignore: projectPath }, function(err){
if(err) console.log(err)
helpers.ls(setup.publicPath, function(err, results){
async.each(results, compileFile, function(err){
if(err){
callback(err)
}else{
async.each(results, copyFile, function(err){
setup.config['harp_version'] = pkg.version
delete setup.config.globals
callback(null, setup.config)
})
}
})
})
})
}
The first portion defines the output path as specified by the call to harp compile via the command line (source here). The default, as you can see, is www. The callback is a callback function passed by the command line utility which is not configurable.
The next part starts by calling the setup function in the helpers module. For the sake of brevity, we won’t go into the specific code of the function (feel free to look for yourself), but essentially it reads the site configuration (i.e. harp.json).
You may also notice a call to something called terraform. This will come up again within this function. Terraform is actually a separate project required by Harp that is the basis of its asset pipeline. The asset pipeline is where the hard work of compiling and building the finished site gets done (we’ll look at Terraform code in a little bit).
The next portion of code, as it states, tries to prevent you from specifying an output directory that would inadvertently overwrite your source code (which would be bad as you’d lose any work since your last commit).
The compileFile and copyFile functions are fairly self-explanatory. The compileFile function relies on Terraform to do the actual compilation. Both of these functions drive the prime function which uses a helper function (fs) to walk the directories, compiling or copying files as necessary in the process.
Terraform
As I discussed, Terraform does the grunt work for compiling the Jade, Markdown, Sass and CoffeeScript into HTML, CSS and JavaScript (and assembling these pieces as defined by Harp). Terraform is made up of a number of files that define its processors for JavaScript, CSS/stylesheets, and templates (which, in this case, includes Markdown).

Within each of these folders is a processors folder that contains the code for each specific processor that Terraform (i.e. Harp) supports. For example, in the templates folder are files that form the basis for compiling EJS, Jade, and Markdown files.

I won’t delve into the code for each of these, but, for the most part, they rely upon external npm modules that handle the supported processor. For example, for Markdown support, it depends upon Marked.
The core logic of Terraform is contained in its render function.
/**
* Render
*
* This is the main method to to render a view. This function is
* responsible to for figuring out the layout to use and sets the
* `current` object.
*
*/
render: function(filePath, locals, callback){
// get rid of leading slash (windows)
filePath = filePath.replace(/^\\/g, '')
// locals are optional
if(!callback){
callback = locals
locals = {}
}
/**
* We ignore files that start with underscore
*/
if(helpers.shouldIgnore(filePath)) return callback(null, null)
/**
* If template file we need to set current and other locals
*/
if(helpers.isTemplate(filePath)) {
/**
* Current
*/
locals._ = lodash
locals.current = helpers.getCurrent(filePath)
/**
* Layout Priority:
*
* 1. passed into partial() function.
* 2. in `_data.json` file.
* 3. default layout.
* 4. no layout
*/
// 1. check for layout passed in
if(!locals.hasOwnProperty('layout')){
// 2. _data.json layout
// TODO: Change this lookup relative to path.
var templateLocals = helpers.walkData(locals.current.path, data)
if(templateLocals && templateLocals.hasOwnProperty('layout')){
if(templateLocals['layout'] === false){
locals['layout'] = null
} else if(templateLocals['layout'] !== true){
// relative path
var dirname = path.dirname(filePath)
var layoutPriorityList = helpers.buildPriorityList(path.join(dirname, templateLocals['layout'] || ""))
// absolute path (fallback)
layoutPriorityList.push(templateLocals['layout'])
// return first existing file
// TODO: Throw error if null
locals['layout'] = helpers.findFirstFile(root, layoutPriorityList)
}
}
// 3. default _layout file
if(!locals.hasOwnProperty('layout')){
locals['layout'] = helpers.findDefaultLayout(root, filePath)
}
// 4. no layout (do nothing)
}
/**
* TODO: understand again why we are doing this.
*/
try{
var error = null
var output = template(root, templateObject).partial(filePath, locals)
}catch(e){
var error = e
var output = null
}finally{
callback(error, output)
}
}else if(helpers.isStylesheet(filePath)){
stylesheet(root, filePath, callback)
}else if(helpers.isJavaScript(filePath)){
javascript(root, filePath, callback)
}else{
callback(null, null)
}
}
(If you were reading all this code closely, you likely noticed TODO’s, typos, and even a funny „understand again why we are doing this” comment. That’s real life coding!)
The majority of the code in the render function is about handling templates. Things like CoffeeScript and Sass fundamentally render on a one-to-one basis. For example, style.scss will render to style.css. Even if it has includes, that is handled by the renderer. The very end of the render function deals with these types of files.
Layouts in Harp, on the other hand, are nested within each other in a variety of manners that can even depend upon configuration. For example, about.md might be rendered within the default _layout.jade (where, exactly, is determined by the use of != yield within that layout). However, _layout.jade might include multiple other layouts within itself by way of the partial support in Harp.
Partials are a way of splitting up a template into multiple files. They are especially useful for code reuse. For instance, I might put the site header inside a partial. Partials are important for making layouts within a static site generator maintainable but they also add a good deal of complexity to the logic of compiling templates. This complexity is handled within the partial function of the templates processor.
Finally, you could override the default layout by specifying a specific layout or no layout at all for a particular file within the _data.json configuration file. All of these scenarios are handled (and even numbered) within the logic of the render function.
That’s Not So Complicated, Is It?
To make this digestible, I’ve skipped over a ton of additional detail. At its core, every static site generator I’ve ever used (and I’ve used a bunch) functions similarly: a set of rules, conventions, and configuration that is run through compilers for the various supported markups. Perhaps that is why there are a ridiculous number of static site generators out there.
That being said, I wouldn’t want to build my own!
My Report & Book
If you are interested in learning how to build sites using a static site generator, I’ve authored a report and co-authored a book for O’Reilly that might interest you. My report, simply titled Static Site Generators is free and attempts to establish the history, landscape, and basics behind static site generators.

The book that I co-authored with Raymond Camden is called Working with Static Sites and is available as an early release, but should be available in print soon.
What Really Makes a Static Site Generator? is a post from CSS-Tricks
This browser tweak saved 60% of requests to Facebook
Post pobrano z: This browser tweak saved 60% of requests to Facebook
Ben Maurer & Nate Schloss:
The browser’s reload button exists to allow the user to get an updated version of the current page. In order to meet this goal, when you reload, browsers revalidate the page that you are currently on, even if that page hasn’t expired yet. However, they also go a step further and revalidate all sub-resources on the page — things like images and JavaScript files.
So even if you’ve set proper expires headers for resources, hitting that reload button (which people must do a ton at Facebook) still requires server round trips to revalidate assets (sometimes).
They worked with Chrome:
After fixing this, Chrome went from having 63% of its requests being conditional to 24% of them being conditional.
And Firefox:
Firefox implemented a proposal from one of our engineers to add a new cache-control header for some resources in order to tell the browser that this resource should never be revalidated.
So if you’re using URLs for assets that never change (if they change, they’ll be at a new URL) in Chrome you’ll benefit automatically, and in Firefox you should use their new header.
Direct Link to Article — Permalink
This browser tweak saved 60% of requests to Facebook is a post from CSS-Tricks
Basic Shapes & Path… Never the Twain Shall Meet?
Post pobrano z: Basic Shapes & Path… Never the Twain Shall Meet?
There are some values available in CSS that allow shapes to be drawn. For example, there is a circle() function that is a valid value for a couple of CSS properties. „Drawn” might not be the right word, though. It’s not like in SVG where you can create a <circle> element and it will literally draw a circle.
These shapes in CSS are for other things. Namely: clip-path, which is for making clipping masks, and shape-outside, for flowing text around shapes.
There are some other CSS properties that use SVG-like shapes for doing what they do. For example, offset-path is part of animating elements along vector paths, using the path() function. Paths are awesome. They are the ultimate drawing element, as they can draw anything, and all the other shapes are essentially syntactic sugar for paths.
What are the basic shapes?
There are four basic shapes:
polygon()circle()ellipse()inset()
What are paths?
Paths come from SVG. They have a special syntax that allows them to draw anything.
<path d="M 25,100 C 25,150 75,150 75,100 S 100,25 150,75" />
path("M 25,100 C 25,150 75,150 75,100 S 100,25 150,75");
This is where things get kinda weird
- The
clip-pathandshape-outsideproperties can take all the „basic shapes” likecircle()andpolygon(), but notpath(). - The
offset-pathproperties can takepath(), but not the „basic shapes”. - You can control the
dattribute of a<path>through CSS also, but not the attributes of many other SVG elements.
I’m not really sure why any of this is, and I’m sure things will change in time, but it’s good to know about.
Let’s elaborate.
clip-path allows Basic Shapes (but not path())
Say you wanted to clip square avatars into polygons, for a fun design. You can! The image is might be an HTML element like:
<img src="avatar.jpg" alt="User Avatar" class="avatar">
.avatar {
clip-path: polygon(0% 5%, 100% 0%, 100% 85%, 65% 80%, 75% 100%, 40% 80%, 0% 75%);
}
See the Pen Clipped Avatars by Chris Coyier (@chriscoyier) on CodePen.
But let’s say you want to clip the avatar like this:

Well, you can’t. Not directly in CSS anyway. Those curves require a path, and clip-path don’t do path. Fortunatly, clip-path does take a url(), which will accept the ID of a <clipPath> element.
See the Pen Clipped Avatars by Chris Coyier (@chriscoyier) on CodePen.
offset-path allows path (but not Basic Shapes)
Say we want to move an object along the outside of that speech bubble shape we just used. The offset-path property is just for that.
<div class="move-me"></div>
.move-me {
offset-path: path("M100.5,39.47C100.5,58.3,83.36,74,60.58,77.64l16.85,19.9L33.94,76.25C14.47,70.92.5,56.47.5,39.47c0-21.52,22.39-39,50-39S100.5,17.95,100.5,39.47Z");
animation: move 3s linear infinite;
}
@keyframes move {
100% { motion-offset: 100%;}
}
See the Pen offset-path on path by Chris Coyier (@chriscoyier) on CodePen.
But what if you want to move the element in a circle? The basic shape version of a circle has a super easy syntax, like circle(50% at 50% 50%); But unfortunately, the basic shapes aren’t supported. The spec allows for them, but they don’t work. It kinda makes sense, because… how would you define which direction to travel?
You can still animate in a circle, because the all-powerful path can draw a circle, like:
.move-me {
/* a circle */
offset-path: path("M100,50a50,50,0,1,1-50-50A50,50,0,0,1,100,50Z");
animation: move 3s linear infinite;
}
@keyframes move {
100% { motion-offset: 100%;}
}
And those commands dictate a direction naturally. There are also other ways to animate in a circle.
shape-outside allows Basic Shapes (but not path())
Say you wanted to wrap some text around an egg shape, because I dunno, you were setting some text of Alice talking to Humpty Dumpty. The egg shape is a good excuse to use the ellipse() Basic Shape.
<div class="page-wrap">
<div class="egg"></div>
<p>"I don't know what you mean by 'glory,'" Alice said.</p>
<p>Humpty Dumpty smiled contemptuously. "Of course you don't—till I tell you. I meant 'there's a nice knock-down argument for you!'"</p>
...
.egg {
float: left;
shape-outside: ellipse(120px 160px at 50% 50%);
width: 280px;
height: 320px;
}
We’d probably set an identical clip-path (to actually make the egg shape) and colorize it:
See the Pen Shape Outside Egg by Chris Coyier (@chriscoyier) on CodePen.
But what if you wanted to make some text wrap around a curved shape, like shown here in Illustrator:

Unfortunately, shape-outside doesn’t take path(), so you can’t. But you kinda can. It does take url(), in which you can use to link to an image (doesn’t even have to be SVG, but SVG makes good sense). The image can have a nice curvy path, like we’re shooting for:
See the Pen Wrap Text Around Curve by Chris Coyier (@chriscoyier) on CodePen.
The url() can even be a data URL. Also note that any element using shape-outside must be floated, a limitation that might be resolved with CSS Exclusions.
<path> takes path()
Here’s one that starts out making logical sense. Say you have a path:
<svg>
<path d=" ... " />
</svg>
You can change the shape of that path through CSS, say through a hover:
svg:hover path {
d: path(" ... ");
}
See the Pen Change path on hover by Chris Coyier (@chriscoyier) on CodePen.
You can even transition the shape, if it happens to be path data with the same amount of points.
It does get a bit confusing though. Say you have a <polygon> instead.
<svg>
<polygon points=" ... " />
</svg>
How do you update it with CSS?
polygon {
/* Nope */
points: " ... ";
/* Nope */
points: points(" ... ");
/* Nope */
points: polygon(" ... ");
}
There isn’t a way, that I know of. Which seems weird as polygon is otherwise supported all over the place. I imagine part of problem is that the polygon() function is different from the points attribute. The polygon() function takes percentages and numbers with units in CSS, whereas the points attribute takes unitless numbers (like everything in SVG). They are different beasts, and that overlap is awkward.
It’s also not that SVG shapes that overlap with Basic Shapes can’t be altered. All of <circle>’s attributes, for example, can be altered with CSS:
svg:hover circle {
cx: 40;
cy: 40;
r: 40;
}
See the Pen Altering Circle Attributes by Chris Coyier (@chriscoyier) on CodePen.
Long story short: there is usually a way to get done what you want to get done, but it’s confusing what is/isn’t supported where.
Basic Shapes & Path… Never the Twain Shall Meet? is a post from CSS-Tricks
A Poll on How Developers Run WordPress Locally
Post pobrano z: A Poll on How Developers Run WordPress Locally
I really have no idea how this will turn out. I suspect a ton of you have run or are currently running WordPress locally, but I have no clear guess on what the most popular way is to do that right now.
Note: There is a poll embedded within this post, please visit the site to participate in this post’s poll.
Let’s limit the poll to how you are actually doing it, not how you wish you were doing it. And if you don’t work with WordPress, but do work with a project that has similar dependencies (i.e. a server-side language, a database, and a web server), feel free to vote based on that project.
A Poll on How Developers Run WordPress Locally is a post from CSS-Tricks
The Easiest Way to Find a New Job
Post pobrano z: The Easiest Way to Find a New Job
As a highly talented developer or designer, shouldn’t companies apply to you? On Hired the traditional process of finding a job is completely reversed. Hired expedites the job search process through an efficient system of:
- Companies competing for top talent with visibility into a candidate’s traction on Hired, driving rapid turnaround times from interview to final offer.
- Free personalized support on your job hunt. On Hired our Talent Advocates have your back, whether it’s negotiating compensation or preparing for interviews.
- Upfront salary, equity and bonus details in every interview request.
Direct Link to Article — Permalink
The Easiest Way to Find a New Job is a post from CSS-Tricks
Intro to Vue.js: Animations
Post pobrano z: Intro to Vue.js: Animations
This is the fifth part in a five-part series about the JavaScript framework, Vue.js. In this last part of the series, we’ll cover Animations (if you know me at all, you probably knew this was coming). This is not intended to be a complete guide, but rather an overview of the basics to get you up and running so you can get to know Vue.js and understand what the framework has to offer.

Article Series:
- Rendering, Directives, and Events
- Components, Props, and Slots
- Vue-cli
- Vuex
- Animations (You are here!)
Some background
There are built-in <transition> and <transition-group> components that allow for both CSS and JS hooks. If you come from React, the concept behind the transition component will be familiar to you, because it works similarly to ReactCSSTransitionGroup in relationship to lifecycle hooks, but it has some notable differences that make nerds like me excited.
We’ll start off by talking about CSS Transitions, then move on to CSS Animations, then we’ll talk about JS Animation Hooks and then animating with Lifecycle Methods. Transitioning state is out of the scope of this article, but it is possible. Here’s a well-commented Pen I made that does just that. I could probably be convinced to write that article too, once I take a long nap.
Transitions vs. Animations
Just in case you’re confused by why Transitions and Animations have different sections in this article, let me explain that though they sound similar, they’re a bit different. A transition basically works by interpolating the values from state to another. We can do great things with them, but they are rather simple. Here, to there, and back again.
Animations are a bit different in that you can make multiple states occur within one declaration. For instance, you could set a keyframe 50% into the animation, and then another totally different thing can occur at 70%, and so on. You can even chain many animations with delays for really complex movement. Animations have the ability to behave like transitions, where we only interpolate something from here to there, but transitions can’t have multiple steps like an animation (not without some crazy hacky development that it’s not really supposed to be used for.)
In terms of tools, both are useful. Think of transitions as a saw and animations as a powersaw. Sometimes you just need to saw one thing and it would be silly to go out and buy really expensive equipment. For other more robust projects, it makes more sense to make the powersaw investment.
Now that we have those basics down, let’s talk about Vue!
CSS Transitions
Let’s say we have a simple modal. The modal shows and hides on a click of a button. Based on the previous sections, we already know that we might: make a Vue instance with a button, make a child component from that instance, set the data on the state so that it toggles some sort of boolean and add an event handler to show and hide this child component. We could use v-if or v-show to toggle the visibility. We might even use a slot to pass the button toggle into the modal as well.
<div id="app">
<h3>Let's trigger this here modal!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Hide child</span>
<span v-else>Show child</span>
</button>
<app-child v-if="isShowing" class="modal">
<button @click="toggleShow">
Close
</button>
</app-child>
</div>
<script type="text/x-template" id="childarea">
<div>
<h2>Here I am!</h2>
<slot></slot>
</div>
</script>
const Child = {
template: '#childarea'
};
new Vue({
el: '#app',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
},
components: {
appChild: Child
}
});
See the Pen by Sarah Drasner.
This works, but it’s pretty jarring to have that modal just pop in our faces like that. 😳
We’re already mounting and unmounting that child component with v-if, so Vue will let us track changes on that event if we wrap that conditional in a transition component:
<transition name="fade">
<app-child v-if="isShowing" class="modal">
<button @click="toggleShow">
Close
</button>
</app-child>
</transition>
Now, we could just use <transition> out of the box. This will give us a v- prefix for some transition hooks we can use in our CSS. It will offer enter/leave which is the position that the animation starts with on the first frame, enter-active/leave-active while the animation is running- this is the one you’d place the animation properties themselves on, and enter-to/leave-to, which specifies where the element should be on the last frame.
I’m going to use a graphic from the docs to show this because I think it describes the classes as beautifully and clearly as possible:

Personally, I don’t usually work with the default v- prefix. I’ll always give the transition a name so that there are no collisions if I want to eventually apply another animation. It’s not hard to do so, as you can see above, we simply added a name attribute to the transition component: name="fade".
Now that we have our hooks, we can create the transition using them:
.fade-enter-active, .fade-leave-active {
transition: opacity 0.25s ease-out;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
The .fade-enter-active and .fade-leave-active classes will be where we apply the actual transition. This is normal CSS, you can pass in cubic-beziers for eases, delays, or specify other properties to transition. Truthfully, this would also work just as well if you placed the transition in these classes on the component classes themselves as a default. These don’t necessarily need to be defined by the transition component hooks. They’ll just chill there, and wait until that property changes and use it to transition if it does. (so you would still need the transition component and .fade-enter, .fade-leave-to). The one reason I do use it on the enter-active and leave-active classes is that I can reuse the same transition for other elements as well, and not run around the codebase applying the same default CSS to each instance.
Another thing to note here: I’m using ease-out for both active classes. This works and looks fine for something like opacity. But you may find that if you’re transitioning properties such as transform, you might want to separate the two and use ease-out for the enter-active class and ease-in for the enter-leave class (or cubic-beziers that vaguely follow the same curve). I find it makes the animation look more… classy (har har).
You can see we’ve also set the .fade-enter and the .fade-to to opacity: 0. These will be the first and last positions of the animation, the initial state as it mounts, the end state as it unmounts. You may think you need to set opacity: 1 on .fade-enter-to, and .fade-leave, but that is unnecessary as it’s the default state for the component, so it would be redundant. CSS transitions and animations will always use the default state unless told otherwise.
See the Pen by Sarah Drasner.
This works nicely! But what would happen if we wanted to make that background content fade out of view, so that the modal took center stage and the background lost focus? We can’t use the <transition> component, as that component works based on something being mounted or unmounted, and the background is just sticking around. What we can do is transition classes based on the state, and use the classes to create CSS transitions that alter the background:
<div v-bind:class="[isShowing ? blurClass : '', bkClass]">
<h3>Let's trigger this here modal!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Hide child</span>
<span v-else>Show child</span>
</button>
</div>
.bk {
transition: all 0.1s ease-out;
}
.blur {
filter: blur(2px);
opacity: 0.4;
}
new Vue({
el: '#app',
data() {
return {
isShowing: false,
bkClass: 'bk',
blurClass: 'blur'
}
},
...
});
See the Pen by Sarah Drasner.
CSS Animation
Now that we understand how transitions work, we can build off of those core concepts to create some nice CSS animations. We’ll still use the <transition> component, and we’ll still give it a name, allowing us to have the same class hooks. The difference here will be that instead of just setting the final state and saying how we want it to interpolate between beginning and end, we’ll use @keyframes in CSS to create fun and lovely effects.
In the last section, we talked a little about how you can designate a special name for the transition component that we can then use as class hooks. But in this section, we’ll go a step further, and apply different class hooks to different sections of the animation. You’ll recall that enter-active and leave-active is where all the juicy business of animating happens. We can set different properties on each of these class hooks, but we can go one step further and give special classes to each instance:
enter-active-class="toasty"
leave-active-class="bounceOut"
This means we can reuse those classes or even plug into the classes from CSS animation libraries.
Let’s say we want a ball to bounce in and roll out:
<div id="app">
<h3>Bounce the Ball!</h3>
<button @click="toggleShow">
<span v-if="isShowing">Get it gone!</span>
<span v-else>Here we go!</span>
</button>
<transition
name="ballmove"
enter-active-class="bouncein"
leave-active-class="rollout">
<div v-if="isShowing">
<app-child class="child"></app-child>
</div>
</transition>
</div>
For the bounce, we’d need a lot of keyframes if we want to do this in CSS (though in JS this could be one line of code), we also will use a SASS mixin to keep our styles DRY (don’t repeat yourself). We’ve also designated the .ballmove-enter class to let the component know that it should start offscreen:
@mixin ballb($yaxis: 0) {
transform: translate3d(0, $yaxis, 0);
}
@keyframes bouncein {
1% { @include ballb(-400px); }
20%, 40%, 60%, 80%, 95%, 99%, 100% { @include ballb() }
30% { @include ballb(-80px); }
50% { @include ballb(-40px); }
70% { @include ballb(-30px); }
90% { @include ballb(-15px); }
97% { @include ballb(-10px); }
}
.bouncein {
animation: bouncein 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
.ballmove-enter {
@include ballb(-400px);
}
For rolling the ball out, you can see that we need to nest two different animations. This is because the transform is being applied to the entire child component, and spinning the whole thing would result in a huge rotation. So we’ll move the component across the screen with a translation, and spin the ball within with a rotation:
@keyframes rollout {
0% { transform: translate3d(0, 300px, 0); }
100% { transform: translate3d(1000px, 300px, 0); }
}
@keyframes ballroll {
0% { transform: rotate(0); }
100% { transform: rotate(1000deg); }
}
.rollout {
width: 60px;
height: 60px;
animation: rollout 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
div {
animation: ballroll 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
}
See the Pen Ball Bouncing using Vue transition and CSS Animation by Sarah Drasner (@sdras) on CodePen.
Sweet, Sweet Transition Modes
Do you recall when I said that Vue offers some really nice sugary bits in transitions that make nerds like me happy? Here’s a small one that I really love. If you try to transition one component in while another component is leaving, you’ll end up with this really weird moment where both exist at the same time and then snap back into place (this small example from the Vue docs):

Vue offers transition modes, which will allow you to transition one component out while bringing another component in without any strange position flashing or blocking. It does so by ordering the transitioning instead of having them occur at the same time. There are two modes to choose from:
In-out: The current element waits until the new element is done transitioning in to fire
Out-in: The current element transitions out and then the new element transitions in.
Check out the demo below. You can see the mode- out-in on the transition component so that it appears that only one piece is flipping:
<transition name="flip" mode="out-in">
<slot v-if="!isShowing"></slot>
<img v-else src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/cartoonvideo14.jpeg" />
</transition>
See the Pen Vue in-out modes by Sarah Drasner (@sdras) on CodePen.
If we were to take out that mode, you can see that one flip obscures the other, and the animation looks jarring, not at all the effect we want to achieve:
See the Pen Vue in-out modes – no modes contrast by Sarah Drasner (@sdras) on CodePen.
JS Animation
We have some nice JS hooks that are very easy to use or not use as we see fit for our animation. All hooks pass in the el parameter (short for element) except on the actual animation hooks, enter and leave, which also pass done as a parameter, which, you guessed it, is used to tell Vue that the animation is completed. You’ll notice we’re also binding CSS to a falsy value to let the component know we’ll be using JavaScript instead of CSS.
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-Leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
:css="false">
</transition>
At the most basic level, this is really what you would need for an entrance and exit animation, including the corresponding methods:
<transition
@enter="enterEl"
@leave="leaveEl"
:css="false">
<!-- put element here-->
</transition>
methods: {
enterEl(el, done) {
//entrance animation
done();
},
leaveEl(el, done) {
//exit animation
done();
},
}
Here’s an example of how I would use this to plug into a GreenSock timeline:
new Vue({
el: '#app',
data() {
return {
message: 'This is a good place to type things.',
load: false
}
},
methods: {
beforeEnter(el) {
TweenMax.set(el, {
transformPerspective: 600,
perspective: 300,
transformStyle: "preserve-3d",
autoAlpha: 1
});
},
enter(el, done) {
...
tl.add("drop");
for (var i = 0; i < wordCount; i++) {
tl.from(split.words[i], 1.5, {
z: Math.floor(Math.random() * (1 + 150 - -150) + -150),
ease: Bounce.easeOut
}, "drop+=0." + (i/ 0.5));
...
}
}
});
See the Pen Vue Book Content Typer by Sarah Drasner (@sdras) on CodePen.
Two of the more interesting things to note in the above animation, I’m passing {onComplete:done} as a parameter to the Timeline instance, and I’m using the beforeEnter hook to place my TweenMax.set code, which allows me to set any properties on the words I need for the animation before it happens, in this case, things like transform-style: preserve-3d.
It’s important to note that you can also set what you want for the animation directly in the CSS as the default state as well. People sometimes ask me how to decide what to set in the CSS and what to set in TweenMax.set. As a rule of thumb, I generally put any properties I need specifically for the animation into the TweenMax.set. That way if something in the animation changes and I need to update it, it’s already part of my workflow.
Animations in Lifecycle Hooks
All of this is really nice, but what happens if you need to animate something very complex, something that works with a ton of DOM elements? This is a really nice time to use some lifecycle methods. In the following animation, we have used both the <transition> component as well as the mounted() method to create some animations.
See the Pen Vue Weather Notifier by Sarah Drasner (@sdras) on CodePen.
When we transition a single element, we’ll use the transition component, for instance, when the stroke around the phone button shows up:
<transition
@before-enter="beforeEnterStroke"
@enter="enterStroke"
:css="false"
appear>
<path class="main-button" d="M413,272.2c5.1,1.4,7.2,4.7,4.7,7.4s-8.7,3.8-13.8,2.5-7.2-4.7-4.7-7.4S407.9,270.9,413,272.2Z" transform="translate(0 58)" fill="none"/>
</transition>
beforeEnterStroke(el) {
el.style.strokeWidth = 0;
el.style.stroke = 'orange';
},
enterStroke(el, done) {
const tl = new TimelineMax({
onComplete: done
});
tl.to(el, 0.75, {
strokeWidth: 1,
ease: Circ.easeOut
}, 1);
tl.to(el, 4, {
strokeWidth: 0,
opacity: 0,
ease: Sine.easeOut
});
},
But when a component first shows up and we have 30 elements or more animating, it would not longer be efficient to wrap each one in a separate transition component. So, we’ll use the lifecycle methods we mentioned in section 3 of this series to hook into the same event that the transition hook is using under the hook: mounted()
const Tornadoarea = {
template: '#tornadoarea',
mounted () {
let audio = new Audio('https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/tornado.mp3'),
tl = new TimelineMax();
audio.play();
tl.add("tornado");
//tornado timeline begins
tl.staggerFromTo(".tornado-group ellipse", 1, {
opacity: 0
}, {
opacity: 1,
ease: Sine.easeOut
}, 0.15, "tornado");
...
}
};
We can really use either depending on what’s more efficient and as you can see, you can create really complex effects. Vue offers a really beautiful and flexible API, not just for creating composable front-end architecture, but also for fluid movement and seamless transitions between views.
Conclusion
This series of articles is not intended to be documentation. Though we’ve covered a lot of ground, there’s still so much more to explore: routing, mixins, server-side rendering, etc. There are so many amazing things to work with. Head over to the very excellent docs and this repo full of examples and resources to dig in further. There is also a book called The Majesty of Vue.js, and courses on Egghead.io and Udemy.
Many thanks to Robin Rendle, Chris Coyier, Blake Newman, and Evan You for proofreading various sections of this series. I hope this series conveys why I’m so excited about Vue and helps you get up and running trying out some of the material!
Article Series:
- Rendering, Directives, and Events
- Components, Props, and Slots
- Vue-cli
- Vuex
- Animations (You are here!)
Intro to Vue.js: Animations is a post from CSS-Tricks
Contest: I’ll Come To Your Office
Post pobrano z: Contest: I’ll Come To Your Office
I’ll fly to you and spend the day! Media Temple is sponsoring it, so it doesn’t cost either of us anything. Only one lucky winner, though. All you gotta do is fill out the form (with your email address) and explain why you’re interested. Enter by February 28, winners picked March 24.
Direct Link to Article — Permalink
Contest: I’ll Come To Your Office is a post from CSS-Tricks
