Css Tricks

Syndicate content
Tips, Tricks, and Techniques on using Cascading Style Sheets.
Updated: 1 hour 23 min ago

Blobs!

Thu, 02/21/2019 - 12:01pm

I was recently a guest editor for an issue of Bizarro Devs. It's a great newsletter! Go sign up! I put in a bunch of links around blobs. Like those weird squishy random shapes that are so "in" right now. Here are those links as well. I'm always a fan of publishing stuff I write ;)

Blobs! Blobs are in! Blobs are — ahem — a bit bizarre. I'll bask in a design like this annual report cover by Matt Pamer all day. I enjoy watching a design trend like this manifest itself in design tooling and become applied in lots of creative and crafty different ways.

We could start with <svg> and draw our own blob using the Pen tool that is pretty much stock in every vector design application. I'm a cheater though, and would probably wind up checking The Noun Project for some blob examples and steal the SVG from there. But sadly, there isn't much there, at least as far as blobs go.

Thank god for... (wait for it)... THE BLOBMAKER:

Once we have a blob, it's just begging to be moved around. Monica Dinculescu shows how to do just that with pure CSS and liberal use of various CSS transforms in a keyframe animation:

See the Pen
CSS only morphing blob
by Monica Dinculescu (@notwaldorf)
on CodePen.

Or we can use a JavaScript library like KUTE.js to get all morph-y, like Heartbeat has done here:

See the Pen
Morphing shapes with KUTE.js
by Heartbeat.UA (@hbagency)
on CodePen.

A library like Greensock could help moving and morphing the blobs around. Greensock even has a plugin that is probably the most powerful morphing tool out there. This Pen uses Greensock, but adds some native SVG filters so that the blobs squish into each other satisfyingly. We could call it the gooey effect:

See the Pen
SVG blob mask
by ATCOM (@Atcom)
on CodePen.

We've only looked at SVG so far, but don't rule out <canvas>! Liam Egan has make this canvas-based blob downright jiggly:

See the Pen
Blob
by Liam Egan (@shubniggurath)
on CodePen.

Why not add a little physics to the party, like gravity, and let them blobs get squishy that way! Hakim El Hattab got it done here:

See the Pen
Blob
by Hakim El Hattab (@hakimel)
on CodePen.

And blobs don't have to be alone! Blobs that are squished together are like fluid. You might get a kick out of Peeke Kuepers article Simulating blobs of fluid.

The post Blobs! appeared first on CSS-Tricks.

Deliver your best work with the help of monday.com

Thu, 02/21/2019 - 11:58am

(This is a sponsored post.)

Here's the situation: You've bashed out a complicated design over two weeks of near full-time effort, gotten everything down to the exact spec of the design file, turn it in for stakeholder review and... you're way off scope. Turns out a few folks on the team put their heads together, made some changes, and never sent you an updated comp.

Boo!

The unfortunate truth is that this happens all too often in front-end development, but it's really no one person's fault because it boils down to simple collective miscommunication and a lack of transparency on the team.

Well, that's where a project management platform like monday.com comes into play. Even if you're on a remote team or sitting in an office with cubicle walls up to the ceiling, monday.com bridges gaps and tears down walls that could throw a project off-track. With powerful and intuitive tools, like instant messaging for those ad hoc meetings, file storage for a centralized repository of assets, and an activity dashboard for catching up on the status of a project at a glance, monday.com brings project out into the light so everyone is in the loop and on the same page.

Seriously, you'll wonder what you ever did without monday.com in your life once you've used it. It does everything any other project management tool can do — from task lists and milestones to budgets and human resources — but does one important thing that separates it from the rest: the personal touch that makes everyone on the team feel valuable, included and heard. That's tough to beat and unique to the project management landscape.

Like most things, seeing is believing, so give monday.com a try today. The first 14 days are on the house and will give you a feel for what makes it so great.

Try it Free

Direct Link to ArticlePermalink

The post Deliver your best work with the help of monday.com appeared first on CSS-Tricks.

CSS Variables + calc() + rgb() = Enforcing High Contrast Colors

Thu, 02/21/2019 - 6:26am

As you may know, the recent updates and additions to CSS are extremely powerful. From Flexbox to Grid, and — what we’re concerned about here — Custom Properties (aka CSS variables), all of which make robust and dynamic layouts and interfaces easier than ever while opening up many other possibilities we used to only dream of.

The other day, I was thinking that there must be a way to use Custom Properties to color an element's background while maintaining a contrast with the foreground color that is high enough (using either white or black) to pass WCAG AA accessibility standards.

It’s astonishingly efficient to do this in JavaScript with a few lines of code:

var rgb = [255, 0, 0]; function setForegroundColor() { var sum = Math.round(((parseInt(rgb[0]) * 299) + (parseInt(rgb[1]) * 587) + (parseInt(rgb[2]) * 114)) / 1000); return (sum > 128) ? 'black' : 'white'; }

This takes the red, green and blue (RGB) values of an element’s background color, multiplies them by some special numbers (299, 587, and 144, respectively), adds them together, then divides the total by 1,000. When that sum is greater than 128, it will return black; otherwise, we’ll get white. Not too bad.

The only problem is, when it comes to recreating this in CSS, we don't have access to a native if statement to evaluate the sum. So,how can we replicate this in CSS without one?

Luckily, like HTML, CSS can be very forgiving. If we pass a value greater than 255 into the RGB function, it will get capped at 255. Same goes for numbers lower than 0. Even negative integers will get capped at 0. So, instead of testing whether our sum is greater or less than 128, we subtract 128 from our sum, giving us either a positive or negative integer. Then, if we multiply it by a large negative value (e.g. -1,000), we end up with either very large positive or negative values that we can then pass into the RGB function. Like I said earlier, this will get capped to the browser’s desired values.

Here is an example using CSS variables:

:root { --red: 28; --green: 150; --blue: 130; --accessible-color: calc( ( ( (var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114) / 1000 ) - 128 ) * -1000 ); } .button { color: rgb( var(--accessible-color), var(--accessible-color), var(--accessible-color) ); background-color: rgb( var(--red), var(--green), var(--blue) ); }

If my math is correct (and it's very possible that it's not) we get a total of 16,758, which is much greater than 255. Pass this total into the rgb() function for all three values, and the browser will set the text color to white.

At this point, everything seems to be working in both Chrome and Firefox, but Safari is a little cranky and gives a different result. At first, I thought this might be because Safari was not capping the large values I was providing in the function, but after some testing, I found that Safari didn't like the division in my calculation for some reason.

Taking a closer look at the calc() function, I noticed that I could remove the division of 1,000 by increasing the value of 128 to 128,000. Here’s how that looks so far:

:root { --red: 28; --green: 150; --blue: 130; --accessible-color: calc( ( ( (var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114) ) - 128000 /* HIGHLIGHT */ ) * -1000 ); } .button { color: rgb( var(--accessible-color), var(--accessible-color), var(--accessible-color) ); background-color: rgb( var(--red), var(--green), var(--blue) ); }

Throw in a few range sliders to adjust the color values, and there you have it: a dynamic UI element that can swap text color based on its background-color while maintaining a passing grade with WCAG AA.

See the Pen
CSS Only Accessible Button
by Josh Bader (@joshbader)
on CodePen.

Putting this concept to practical use

Below is a Pen showing how this technique can be used to theme a user interface. I have duplicated and moved the --accessible-color variable into the specific CSS rules that require it, and to help ensure backgrounds remain accessible based on their foregrounds, I have multiplied the --accessible-color variable by -1 in several places. The colors can be changed by using the controls located at the bottom-right. Click the cog/gear icon to access them.

See the Pen
CSS Variable Accessible UI
by Josh Bader (@joshbader)
on CodePen.

There are other ways to do this

A little while back, Facundo Corradini explained how to do something very similar in this post. He uses a slightly different calculation in combination with the hsl function. He also goes into detail about some of the issues he was having while coming up with the concept:

Some hues get really problematic (particularly yellows and cyans), as they are displayed way brighter than others (e.g. reds and blues) despite having the same lightness value. In consequence, some colors are treated as dark and given white text despite being extremely bright.

What in the name of CSS is going on?

He goes on to mention that Edge wasn’t capping his large numbers, and during my testing, I noticed that sometimes it was working and other times it was not. If anyone can pinpoint why this might be, feel free to share in the comments.

Further, Ana Tudor explains how using filter + mix-blend-mode can help contrast text against more complex backgrounds. And, when I say complex, I mean complex. She even goes so far as to demonstrate how text color can change as pieces of the background color change — pretty awesome!

Also, Robin Rendle explains how to use mix-blend-mode along with pseudo elements to automatically reverse text colors based on their background-color.

So, count this as yet another approach to throw into the mix. It’s incredibly awesome that Custom Properties open up these sorts of possibilities for us while allowing us to solve the same problem in a variety of ways.

The post CSS Variables + calc() + rgb() = Enforcing High Contrast Colors appeared first on CSS-Tricks.

Colorful Typographic Experiments

Wed, 02/20/2019 - 1:05pm

There have been some interesting, boundary-pushing typography-related experiments lately. I was trying to think of a joke like "somethings in the descenders" but I just can't find something that will stand on its own leg without being easy to counter.

Codrin Pavel created a fascinating multi-color typeface called CSSans.

It's not a "font", because a font is a file, like "lato.woff2" or whatever. This is a CSS file, and you write in it like this:

<div class="cssans cssans--center"> <div class="cssans__accessible">Cool News</div> <div class="cssans__word"> <b class="cssans:C"></b> <b class="cssans:o"></b> <b class="cssans:o"></b> <b class="cssans:l"></b> </div> <div class="cssans__word"> <b class="cssans:N"></b> <b class="cssans:e"></b> <b class="cssans:w"></b> <b class="cssans:s"></b> </div> </div>

Note the special <div> at the top with the full word in it, while those empty <b> elements do the actual drawing of the glyphs. I wouldn't call it entirely accessible, as I'd argue part of accessibility is stuff like find-on-page with highlighting and selectable text. But this is obviously an artistic experiment and your implementation could go any number of ways. I'd love to see an attempt at setting transparent SVG <text> over the top of it that is sized the same so that the text is selectable.

Looks like the landing page was built in CodePen Projects!

This technique and its relationship with accessibility is pretty interesting and actually more relevant than you might think. In fact, it looks like Facebook uses a similar span technique to fight ad-blocking.

Harbor Type recently put out Rocher Color, a free color font. Yes, color font. That's a thing. And Rocher Color is actually a color font and a variable font.

Support seems kinda decent to me, but it's complicated because there are a bunch of different kinds all with different support across browsers.

The other story is that they are, well, kinda humongous, size-wise. The woff2 file is probably the most relevant here as it's such a modern feature anyway. The download from the site (RocherColorGX.woff2) clocks in at 178KB. Not something you'd just toss on a page for a single headline probably, considering it's not just weight with fonts — but you're also always fighting the FOUT/FOIT battle.

I think to justify using a beefy color font like this you'd...

  1. Use it quite a bit around the site for dynamic headlines
  2. Customize the colors to be perfect for you (ahead of time)
  3. Make use of the fancy variable font features like the bevel and shadow adjustments (on the fly)

If you don't see yourself doing those things, you might be better off using <svg> with these shapes all expanded out to paths. You could still use this font to make the SVG, assuming your design tool supports this kind of font. You won't get text wrapping or anything, but the file size and loading speed will be much faster. Or you could even use a graphic format like PNG/WebP, and there's no terrible shame in that if you still use a semantic element for the headline (visually hidden, of course). You won't get find-on-page highlighting or select-ability, but might be an OK trade-off for a one-off.

Kenneth Ormandy has rounded up some more interesting typographic experiments in CSS. In his post, he mentions Diana Smith's Pure CSS Font, which builds itself from empty elements and all kinds of fancy CSS trickery to draw the shapes.

The point of this project is right in the header:

For private, SEO-hidden, CAPTCHA-friendly unselectable text. Deter plagiarism and spambots!

Hidden for assistive technology too, so careful there, but it seems to me this project is more about exploring possibilities. After all, it's the letters that power Diana's remarkable CSS paintings like Zigaro.

Don't miss Kenneth's post, as he links to lots more fascinating examples of people being typographers with very unconventional tools. Kenneth takes a crack himself with this fascinating little experiment, using a button there to expose the tricks within:

See the Pen
START Pure CSS Lettering test 1
by Kenneth Ormandy (@kennethormandy)
on CodePen.

The post Colorful Typographic Experiments appeared first on CSS-Tricks.

<span>L</span><span>e</span><span>t</span><span>t</span><span>e</span><span>r</span><span>s</span>

Wed, 02/20/2019 - 11:05am

Did you see this Facebook crap?

"Why do I need a 4Ghz quadcore to run facebook?" This is why. A single word split up into 11 HTML DOM elements to avoid adblockers. pic.twitter.com/Zv4RfInrL0

— Mike Pan (@themikepan) February 6, 2019

I popped over to Facebook to verify that and what I saw was a different and even more nested mess:

They are trying to fight your ad blocker browser extension. Of course they are. I'm sure at their scale not doing this means losing millions of dollars. But I wonder if it's really losing money when you factor in losing trust, and potentially losing people on the platform entirely.

It just feels so rude, doesn't it? Like a user specifically installs technology onto their computer in order to exert some control over what they allow onto their computers and into their eyeballs. And they are saying, "No, we do not respect that choice. We are going to fight your technology with our technology and force feed this stuff onto your computer and your eyeballs." Doesn't sit right.

I'm not unaware that ad blockers have ad adverse effect on the ability for websites to make money. That's quite literally how I make money. But I don't want to do it fighting and at the expense of breaking trust. I want to do it gracefully while building trust.

Anyway.

I wonder what writing HTML to help ad blockers would look like instead:

<!-- start: advertisement --> <div class="ad sponsor paid" id="ad-1" data-ad="true"> <div>Sponsor:</div> <a href="https://sponsor.com" rel="nofollow">Company</span> </div> <!-- end: advertisement -->

The good ones have been doing it for ages.

This span-based lettering stuff makes me think of libraries like Splitting.js and Lettering.js that break up text into individual <span>s for styling reasons.

Turns out that doesn't affect on-page search (i.e. if you search for "dog," you'll find <span>d</span><span>o</span><span>g</span>), but it does affect some screen readers in that they will treat each letter distinctly, which can result in pretty awful audio output, like pauses between letters where you wouldn't expect or want them.

It's totally solvable though!

I just read about how powerful aria-label is via Web Platform News, quoting Amelia Bellamy-Royds:

An aria-label attribute on a button or link effectively replaces the text content of that element with the new label.

It was cool to see that's what Lettering.js does by default! And Splitting.js is figuring out the best method for them, which involves aria-label.

Oh, and as ever, ::nth-letter() would be cool. 2018 recap of a 2011 request.

The post <span>L</span><span>e</span><span>t</span><span>t</span><span>e</span><span>r</span><span>s</span> appeared first on CSS-Tricks.

Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art

Wed, 02/20/2019 - 11:04am

Have you seen Diana Smith's CSS drawings? Stunning. These far transcend the CSS drawings that sort of crudely replicate a flat SVG scene, like I might attempt. We were lucky enough for her to post some of her CSS drawing techniques here last year.

Well, Diana has also listed the top five CSS properties she uses to get these masterpieces done, and they are surprising in their plainness:

  1. border-radius
  2. box-shadow
  3. transform
  4. gradients
  5. overflow

...but of course, layered in trickery!

... for custom rounded elements that are meant to mimic organic objects like faces, it is imperative that you become intimately familiar with all eight available parameters in the border-radius property.

Diana shows her famous Francine drawing with each of the most used properties turned off:

Without border-radius Without transform

Be sure to check out this VICE interview she did as well. She covers gems like the fact that Francine was inspired by American Dad (lol) and that the cross-browser fallbacks are both a fascinating and interesting mess.

Direct Link to ArticlePermalink

The post Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art appeared first on CSS-Tricks.

Social Cards as a Service

Tue, 02/19/2019 - 5:19am

I love the idea of programmatically generated images. That power is close at hand these days for us front-end developers, thanks to the concept of headless browsers. Take Puppeteer, the library for controlling headless Chrome. Generating images from URLs is their default use case:

const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'example.png'}); await browser.close(); })();

That ought to get the ol' mind grape going. What if we had URLs on our site that — with the power of our HTML and CSS skills — created perfect little designs for sharing using dynamic data... then turned them into images and used them for our meta tags?

The first I saw of this idea was Drew McLellan's Dynamic Social Sharing Images. Drew wrote a script to fire up Puppeteer and get the job done.

Since the design part is entirely an HTML/CSS adventure, I'm sure you could imagine a setup where the URL passed in parameters that did things like set copy and typography, colors, sizes, etc. Zeit built exactly that!

The URL is like this:

https://og-image.now.sh/I%20am%20Chris%20and%20I%20am%20**cool**%20la%20tee%20ding%20dong%20da..png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.zeit.co%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fhyper-color-logo.svg

Kind of amazing that you can spin up an entire browser in a cloud function! Netlify also offers cloud functions, and when I mentioned this to Phil Hawksworth, he told me he was already doing this for his blog!

So on a blog post like this one, an image like this is automatically generated:

Which is inserted as meta:

<meta property="og:image" content="https://www.hawksworx.com/card-image/-blog-find-that-at-card.png">

I dug through Phil's repos, naturally, and found his little machine for doing it.

I'm madly envious of all this and need to get one set up for myself.

The post Social Cards as a Service appeared first on CSS-Tricks.

Don’t Get Clever with Login Forms

Tue, 02/19/2019 - 5:18am

Brad points out some UX problems with a variety of apps that are doing things a little outside of the norm when it comes to their login forms. There is already a bunch of things to get right with forms to begin with (e.g. use the right input types, label your inputs, don't have whack password requirements, use SSL, etc.)... OMG why complicate it even more?!

A "password manager test" should be a development best practice here. Does it work cleanly with the built-in browser password manager? How about 1Password and LastPass? No? Give it some love, please and thank you.

Direct Link to ArticlePermalink

The post Don’t Get Clever with Login Forms appeared first on CSS-Tricks.

How @supports Works

Mon, 02/18/2019 - 7:39am

CSS has a neat feature that allows us to test if the browser supports a particular property or property:value combination before applying a block of styles — like how a @media query matches when, say, the width of the browser window is narrower than some specified size and then the CSS within it takes effect. In the same spirit, the CSS inside this feature will take effect when the property:value pair being tested is supported in the current browser. That feature is called @supports and it looks like this:

@supports (display: grid) { .main { display: grid; } }

Why? Well, that's a bit tricky. Personally, I find don't need it all that regularly. CSS has natural fallback mechanisms such that if the browser doesn't understand a property:value combination, then it will ignore it and use something declared before it if there is anything, thanks to the cascade. Sometimes that can be used to deal with fallbacks and the end result is a bit less verbose. I'm certainly not a it's-gotta-be-the-same-in-every-browser kinda guy, but I'm also not a write-elaborate-fallbacks-to-get-close kinda guy either. I generally prefer a situation where a natural failure of a property:value doesn't do anything drastic to destroy functionality.

That said, @supports certainly has use cases! And as I found out while putting this post together, plenty of people use it for plenty of interesting situations.

A classic use case

The example I used in the intro is a classic one that you'll see used in lots of writing about this topic. Here it is a bit more fleshed out:

/* We're gonna write a fallback up here in a minute */ @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; } }

Nice grid! Repeating and auto-filling columns is a sweet feature of CSS grid. But, of course, there are browsers that don't support grid, or don't support all the specific features of it that I'm using above there.

For example, iOS shipped support for CSS grid in version 10.2, but iOS has had flexbox support since version 7. That's a decent gap of people with older iOS devices that do support flexbox but not grid. I'm sure there are more example gaps like that, but you probably get the idea.

I was running on an older version of mobile safari and many many many many many sites were flat out broken that used grid

I’m waiting another year or so before messing about with it

— David Wells (@DavidWells) February 6, 2019

It may be acceptable to let the fallback for this be nothing, depending on the requirements. For example, vertically stacked block-level elements rather than a multi-column grid layout. That's often fine with me. But let's say it's not fine, like a photo gallery or something that absolutely needs to have some basic grid-like structure. In that case, starting with flexbox as the default and using @supports to apply grid features where they're supported may work better...

.photo-layout { display: flex; flex-wrap: wrap; > div { flex: 200px; margin: 1rem; } } @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; > div { margin: 0; } } }

The "fallback" is the code outside of the @supports block (the properties above the block in the example above), and the grid code is either inside or after. The @supports block doesn't change any specificity, so we need the source order to help make sure the overrides work.

Notice I had to reset the margin on the divs inside the @supports block. That's the kind of thing I find a bit annoying. There is just enough crossover between the two scenarios that it requires being super aware of how they impact each other.

Doesn't that make you wish it could be entirely logically separated...

There is "not" logic in @supports blocks, but that doesn't mean it should always be used

Jen Simmons put this example in an article called Using Feature Queries in CSS a few years ago:

/* Considered a BAD PRACTICE, at least if you're supporting IE 11 and iOS 8 and older */ @supports not (display: grid) { /* Isolated code for non-support of grid */ } @supports (display: grid) { /* Isolated code for support of grid */ }

Notice the not operator in the first block. That's checking for browsers that do not support grid in order to apply certain styles to those browsers. The reason this approach is considered bad practice is that the browser support for @supports itself has to be considered!. That's what makes this so dang tricky.

It's very appealing to write code in logically separated @supports blocks like that because then it's starting from scratch each time and doesn't need to be overriding previous values and dealing with those logical mind-benders. But let's go back to the same iOS situation we considered before... @supports shipped in iOS in version 9 (right between when flexbox shipped in iOS 7 and grid shipped in iOS 10.2). That means any flexbox fallback code in a @supports block using the not operator to check for (display: grid) {} support wouldn't work in either iOS 7 or 8, meaning the fallback now needs a fallback from working in browsers it otherwise would have. Phew!

The big reason to reach for @supports is to account for very different implementations of something depending on feature support where it becomes easier to reason and distinguish between those implementations if the blocks of code are separated.

We'll probably get to a point where we can use mutually-exclusive blocks like that without worry. Speaking of which...

@supports is likely to be more useful over time.

Once @supports is supported in all browsers you need to support, then it's good to start using it more aggressively and without having to factor in the complication of considering whether @supports itself is supported. Here's the support grid on that:

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafari2812.122No129Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox9.0-9.246all4.47164

Basically, IE 11 and any iOS device stuck on iOS 8 are the pain points. If your requirements are already past those, then you're good to use @supports more freely.

The irony is that there hasn't been a ton of CSS features shipping that have big clear @supports use cases — but there are some! Apparently, it's possible to test new fancy stuff like Houdini:

Using it on my wedding website to check for Houdini support &#x1f3a9;&#x1f430;

— Sam Richard (@Snugug) February 6, 2019

(I'm not sure entirely what you'd put in the @supports block to do that. Has anyone else done this?)

When @supports isn't doing anything useful

I've seen a good amount of @supports uses in the wild where the end result is exactly as it would be without using it. For example...

@supports (transform: rotate(5deg)) { .avatar { transform: rotate(5deg); } }

On some level, that makes perfect logical sense. If transforms are supported, use them. But it's unnecessary if nothing different is happening in a non-support scenario. In this case, the transform can fail without the @supports block and the result is the same.

Here's another example of that shaking out.

There are browser extensions for playing with @supports

There are two of them!

They are both centered around the idea that we can write @supports blocks in CSS and then toggle them on and off as if we're looking at a rendering of the code in a browser that does or doesn't support that feature.

Here's a video of Keith's tool applied to the scenario using grid with a flexbox fallback:

This is fun to play with and is very neat tech. But in this exact scenario, if I was able to pull off the layout identically with flexbox, then I'd probably just do that and save that little bit of technical debt.

Ire's tool, which she wrote about in the article Creating The Feature Queries Manager DevTools Extension, has a slightly different approach in that it shows the feature queries that you actually wrote in your CSS and provides toggles to flip them on and off. I don't think it works through iframes though, so I popped open Debug Mode to use it on CodePen.

More real world use cases for @supports

Here's one from Erik Vorhes. He's styling some custom checkboxes and radio buttons here, but wraps all of it in a @supports block. None of the styling gets applied unless the block passes the support check.

@supports (transform: rotate(1turn)) and (opacity: 0) { /* all the styling for Erik's custom checkboxes and radio buttons */ }

Here are several more I've come across:

  • Joe Wright and Tiago Nunes mentioned using it for position: sticky;. I'd love to see a demo here! As in, where you go for position: sticky;, but then have to do something different besides let it fail for a non-supporting browser.
  • Keith Grant and Matthias Ott mention using it for object-fit: contain;. Matthias has a demo where positioning trickery is used to make an image sort of fill a container, which is then made easier and better through that property when it's available.
  • Ryan Filler mentions using it for mix-blend-mode. His example sets more opacity on an element, but if mix-blend-mode is supported, it uses a bit less and that property which can have the effect of seeing through an element on its own.
  • .thing { opacity: 0.5; } @supports (mix-blend-mode: multiply) { .thing { mix-blend-mode: multiply; opacity: 0.75; } }
  • Rik Schennink mentioned the backdrop-filter property. He says, "when it's supported the opacity of the background color often needs some fine tuning."
  • Nour Saud mentioned it can be used to detect Edge through a specific vendor-prefixed property: @supports (-ms-ime-align:auto) { }.
  • Amber Weinberg mentioned using it for clip-path because adjusting the sizing or padding of an element will accommodate when clipping is unavailable.
  • Ralph Holzmann mentioned using it to test for that "notch" stuff (environment variables).
  • Stacy Kvernmo mentioned using it for the variety of properties needed for drop capping characters. Jen Simmons mentions this use case in her article as well. There is an initial-letter CSS property that's pretty fantastic for drop caps, but is used in conjunction with other properties that you may not want to apply at all if initial-letter isn't supported (or if there's a totally different fallback scenario).

Here's a bonus one from Nick Colley that's not @supports, but @media instead! The spirit is the same. It can prevent that "stuck" hover state on touch devices like this:

@media (hover: hover) { a:hover { background: yellow; } } Logic in @supports

Basic:

@supports (initial-letter: 4) { }

Not:

@supports not (initial-letter: 4) { }

And:

@supports (initial-letter: 4) and (transform: scale(2)) { }

Or:

@supports (initial-letter: 4) or (-webkit-initial-letter: 4) { }

Combos:

@supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) and (-webkit-appearance: caret) { } JavaScript Variant

JavaScript has an API for this. To test if it exists...

if (window.CSS && window.CSS.supports) { // Apparently old Opera had a weird implementation, so you could also do: // !!((window.CSS && window.CSS.supports) || window.supportsCSS || false) }

To use it, either pass the property to it in one param and the value in another:

const supportsGrid = CSS.supports("display", "grid");

...or give it all in one string mirroring the CSS syntax:

const supportsGrid = CSS.supports("(display: grid)"); Selector testing

At the time of this writing, only Firefox supports this sort of testing (behind an experimental flag), but there is a way to test the support of selectors with @supports. MDN's demo:

@supports selector(A > B) { } You?

Of course, we'd love to see Pens of @supports use cases in the comments. So share 'em!

The post How @supports Works appeared first on CSS-Tricks.

instant.page

Mon, 02/18/2019 - 7:25am

instant.page is a pretty cool project from Alexandre Dieulot. Alexandre has been at this idea for half a decade now, as InstantClick is his and is essentially the same exact idea.

The idea is that there is a significant delay between hovering over a link and clicking that link. Say it takes you 300ms of delay. That 300ms could have been spent preloading the next page. And if you do use that time preloading, that page loads that much faster.

This new project makes use of newer tech to get it done. It's hardly any code., the core of which is appending a <link rel="prefetch" href=""> to the document of the link you're about to click/touch.

The page encourages you to hotlink the script, which means possible cache-hits in case you've already visited a page using this. It's not risky in the way other third-party JavaScript can be because the integrity attribute means that if you trust the code as it is now, it can't ever change unless you change that attribute along with it. It also cleverly uses the type="module" to prevent it from loading anything in browsers that don't support prefetching anyway.

Still, you could self-host it if you wanted. I have no idea who's ponying up the for the bandwidth here, so another risk is a hung script should it stop responding one day.

You could argue that it doesn't do the prefetching as absolutely responsibly as it could. Google's similar quick link library (which we covered here) does two interesting things in which to attempt to be more responsible with prefetching: 1) wait for requestIdleCallback and 2) respects info from navigator.connection, like a user enabling data-saver mode.

Direct Link to ArticlePermalink

The post instant.page appeared first on CSS-Tricks.

IE10-Compatible Grid Auto-Placement with Flexbox

Mon, 02/18/2019 - 6:15am

If you work on web applications that support older browsers, and have lusted after CSS Grid from the sidelines like I have, I have some good news: I've discovered a clever CSS-only way to use grid auto-placement in IE10+!

Now, it's not actually CSS Grid, but without looking at the code itself, you wouldn't be able to tell. The HTML structure looks like CSS Grid. It has a defined set of columns with an undefined amount of rows and it has gutters that support borders and shadows on the cells without hacks. But what’s actually happening behind the scenes is a combination of flexbox and margins.

In this article, I'll walk through the approach. Here’s a demo of what we’re looking at:

See the Pen
IE10-compatible CSS-Grid-like column layout
by Brian Holt (@bholtbholt)
on CodePen.

Auto-flowing rows with flexbox wrap Flexbox-created auto-placement grid

Getting the basic grid setup is very simple. If you're at all familiar with flexbox, I'm certain you've already guessed flex-wrap: wrap is the trick here. And you'd be right.

Let's get the HTML markup in place before we write any CSS. We want it to resemble the same structure as if we were using auto-placement — a .grid container and an undefined number of .grid__cells.

<div class="grid"> <div class="grid__cell">...</div> ... </div>

We set three grid breakpoints. A single-column, two-column, and three-column layout for mobile-devices, small screens, and medium screens, respectively. I'm using the breakpoints used in Bootstrap for this article, though we’d want to define them at actual points where the layout breaks if we were working with real content.

$screen-sm-min: 768px; $screen-sm-max: 991px; $screen-md-min: 992px; Mobile-first grid collapses into a single column

A mobile-first approach means our single-column layout is already complete since each .grid__cell is already a block. We set .grid to become a flexbox container after the first breakpoint, and wrap cells.

@media (min-width: $screen-sm-min) { .grid { display: flex; flex-wrap: wrap; } }

Our two- and three-column layouts need explicit widths and flex properties; otherwise they'll cram onto a single line. While testing IE10, I experienced unexpected behavior with the flex-basis property, and found setting an explicit width with flex-basis: auto was more consistent. This didn't seem to be a problem with IE11 though.

.grid__cell { min-width: 0; flex: 1 1 auto; } // Two-column grid @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: 50%; .grid__cell { width: $width; } } // Three-column grid @media (min-width: $screen-md-min) { $width: 33.33%; .grid__cell { width: $width; } }

We don't need to wrap .grid__cell in a media query since its flex properties won't have the effect when the parent isn't a flexbox container. We also define an upper-limit to the two-column media query so it doesn't affect the three-column grid.

And that's it! We now have a responsive, fluid, wrapping flexbox grid. The easy part is done… well, as long as we only ever have items that are multiples of two and three. With flex: 1 1 auto, the last item will always take up any remaining space in the last row.

Two-column grid on smaller screens Three-column grid on large screens Aligning cells in the last row

The elusive last row is why we're here, right? By default, each cell will stretch to the end of the row in a flexbox layout, but grid leaves a blank spot. How do we do that in flexbox? With pseudo-elements!

The trick is to add a pseudo-element to the .grid container and set it like a cell. We define the :after pseudo-element cell at each of our breakpoints with the same width as a real cell.

@media (min-width: $screen-sm-min) { .grid { ... &:after { content: ''; display: block; flex: 1 1 auto; } } } @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: 50%; .grid:after { width: $width; } } @media (min-width: $screen-md-min) { $width: 33.33%; .grid:after { width: $width; } }

This creates a fake cell that will push against our real cells and align our two-column grid when the cells are odd. Leaving its height undefined allows it to collapse to nothing when the cells are even.

Two-column grid with odd cells, snapping into place

Our three-column grid is a bit more complex because we need to handle multiple states, like when there is one empty cell and when there are two empty cells.

Three-column grid with one empty cell

Our one empty cell state is already handled because it isn't really any different from one empty cell in two columns. The :after cell has its width set and completes the row. The story changes when there are two empty cells though because flex: 1 1 auto rears its head again: the last cell now stretches across 50% of the width when pushed against the pseudo-element.

Three-column grid with two empty cells

Using CSS :nth-of-type selectors, we can target the first column in each row. Since our rows are multiples of three, we target them with 3n then count backwards by 2 to get the first element in each row.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2) { background-color: red; } } } Targeting the first cell in each three-column row

We're broadly targeting all the cells in the first column, but we need to limit the selection to only the last row. Actually, we need to limit it to when it's the last cell in the first column of the last row. Luckily, there's a handy pseudo-selector for targeting the last item of its kind. We chain :last-of-type to create the logical statement.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2):last-of-type { background-color: red; } } }

Now that we have the last cell in the first column of the last row selected, we use a margin to push the :after cell to the last column and fill the middle cell.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2):last-of-type { margin-right: $width; } } }

Here's our flexbox-defined-auto-placement-grid-imitator in full. Look at its beautifully lined up rows. I bet you can't even tell it's not CSS Grid!

Our complete three-column grid. Adding gutters with margins

CSS Grid's spec has a column and row gap to provide space between each cell. Creating gutters in flexbox is much more challenging. It looks like it's coming to flexbox, but we're not there yet…and IE will never be.

In Daniel Tonon’s guide on CSS Grid in IE, he used an inner-cell div with negative margins, borders, a bit of padding, and overflow: hidden. While maybe a bit hacky, the effect works, but it breaks our desire to maintain CSS Grid-like HTML structure. The approach I prefer might feel a bit crude, but I also found it the easiest to read and understand. Further, it continues using :nth-of-type pseudo-selectors which makes the overall approach feel consistent.

We want gaps between the cells, but not around the outside. We also want our cells to sit flush with the container.

Gaps between the cells, not on the outside.

Our mobile or single-column grid only needs a bottom margin on the cells. We add that and override the very last cell with margin-bottom: 0 so the cell fits flush against the container. Normally I'd use initial, but there's no support in IE.

$col-gap: 16px; .grid__cell { ... margin-bottom: $col-gap; &:last-of-type { margin-bottom: 0; } } Single-column grid with gaps between each row

Our two- and three-column grids need margins on the right of the cells, no right margins in the last column, and no bottom margins on any of the last row's cells. Because of the margins, we'll also need to recalculate our widths since the cells will wrap if they don't fit.

In a two-column layout, getting the right (or second) column is fairly easy with :nth-of-type(2n) or :nth-of-type(even). I prefer an n-multiplier for consistency with our three-column grid and for calculating the last row.

Our last row is a bit more tricky. When we have odd cells our mobile-first CSS takes care of removing the bottom margins since the cell is the :last-of-type and our :after cell doesn't have margins applied.

Two-columns with even cells

When we have even cells we need to target the second last cell, but only when it is in the first column position. If we didn't qualify it, the second last cell will grow vertically with to match the height of the second last row. We can target it with :nth-of-type(2n-1):nth-last-of-type(2).

@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: calc(50% - #{$col-gap}); .grid__cell { ... margin-right: $col-gap; // Remove margin in last column &:nth-of-type(2n) { margin-right: 0; } // For when the last row is complete // . . // * . &:nth-of-type(2n-1):nth-last-of-type(2) { margin-bottom: 0; } } } Two-columns with even cells that sit flush against the container

Our three-column gutters take the same approach. We add margin-right to all of them, remove it from the third column, and remove bottom margins from the last row. Again our last cell is handled by our mobile-first approach, but now we need to cover when there are two cells in the last row and when when there are three cells. We can qualify our selectors with nth-of-type and nth-last-of-type.

@media (min-width: $screen-md-min) { $width: calc(33% - #{$col-gap}); .grid__cell { ... margin-right: $col-gap; // Remove margin in last column &:nth-of-type(3n) { margin-right: 0; } // For when there two items in the last row // . . . // * . &:nth-of-type(3n-2):nth-last-of-type(2) { margin-bottom: 0; } // For when the last row is complete // . . . // * * . &:nth-of-type(3n-1):nth-last-of-type(2), &:nth-of-type(3n-2):nth-last-of-type(3) { margin-bottom: 0; } } } Three-column grid with gutters and an empty cell

We need to adjust the margin of last cell in the last row when it's alone because of the columns. We use 33% plus a gutter on each side.

@media (min-width: $screen-md-min) { $width: calc(33% - #{$col-gap}); .grid__cell { ... // When there is only one item in the last rpw // Fill the margin so it's like the last item is // double the width // . . . // *-> &:nth-of-type(3n-2):last-of-type { margin-right: calc(33% + #{$col-gap * 2}); } } }

Now our gutters are installed and the grid is complete! Fill them borders, shadows, or whatever your heart desires.

Complete three-column grid with gutters using flexbox. Wrapping up

Here’s the final result one more time:

See the Pen
IE10-compatible CSS-Grid-like column layout
by Brian Holt (@bholtbholt)
on CodePen.

I believe this technique could also support IE9 with minor adjustments, like using inline-blocks instead of flexbox. We could also expand to a four-column grid by adding another breakpoint and using the same approach as the three-column grid. Feel free to use this approach and I hope it helps!

The post IE10-Compatible Grid Auto-Placement with Flexbox appeared first on CSS-Tricks.

The Magic of React-Based Multi-Step Forms

Fri, 02/15/2019 - 5:20am

One way to deal with long, complex forms is to break them up into multiple steps. You know, answer one set of questions, move on to another, then maybe another, and so on and so forth. We often refer to these as multi-step forms (for obvious reasons), but others also take to calling it a “wizard” form.

Multi-step forms can be a great idea! By only showing a few inputs on a screen at a time, the form may feel more digestible and prevent users from feeling overwhelmed by a sea of form fields. Although I haven’t looked it up, I’m willing to say no one enjoys completing a ginormous form — that’s where multiple steps can come in handy.

The problem is that multi-step forms — while reducing perceived complexity on the front end — can feel complex and overwhelming to develop. But, I’m here to tell you that it’s not only achievable, but relatively straightforward using React as the base. So, that’s what we’re going to build together today!

Here’s the final product:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

Let’s build it!

The easiest way to create a multi-step form is to create a container form element that contains all the steps inside of it as components. Here’s a visual showing that container (<MasterForm/>), the components inside of it (<Step1/>, <Step2/>, <Step3/>) and the way states and props are passed between them.

<MasterForm/> serves as the container while three child components inside of it act as each step of the form.

Although it seems to be more complex than a regular form, a multi-step form still uses the same principles as a React form:

  • State is used for storing data and user inputs.
  • Component is used for writing methods and the interface.
  • Props are used for passing data and function into elements.

Instead of having one form component, we will have one parent component and three child components. In the diagram above, <MasterForm/> will send data and functions to the child components via props, and in turn, the child components will trigger a handleChange() function to set values in the state of <MasterForm/>. It’s one big happy family over here!

We'll need a function to move the form from one step to another as well, and we’ll get to that a little later.

The step child (get it?) components will receive props from the <MasterForm/> parent component for value and onChange props.

  • <Step1/> component will render an email address input
  • <Step2/> will render a username input
  • <Step3/> will render a password input and a submit button

<MasterForm/> will supply both data and function into child components, and child components will pass user inputs back to the parent using its props.

Creating the step (child) components

First, we’ll create the form’s child components. We’re keeping things pretty barebones for this example by only using one input per step, but each step could really be as complex as we’d like. Since the child components look almost similar between one another, I’m just gonna show one of them here. But be sure to take a look at the demo for the full code.

class Step1 extends React.Component { render() { if (this.props.currentStep !== 1) { // Prop: The current step return null } // The markup for the Step 1 UI return( <div className="form-group"> <label htmlFor="email">Email address</label> <input className="form-control" id="email" name="email" type="text" placeholder="Enter email" value={this.props.email} // Prop: The email input data onChange={this.props.handleChange} // Prop: Puts data into state /> </div> ) } }

Now we can put this child component into the form’s render() function and pass in the necessary props. Just like in React’s form documentation, we can still use handleChange() to put the user’s submitted data into state with setState(). A handleSubmit() function will run on form submit.

Next up, the parent component

Let’s make the parent component — which we’re all aware by now, we’re calling <MasterForm/> — and initialize its state and methods.

We’re using a currentStep state that will be initialized with a default value of 1, indicating the first step (<Step1/>) of the form. We’ll update the state as the form progresses to indicate the current step.

class MasterForm extends Component { constructor(props) { super(props) // Set the initial input values this.state = { currentStep: 1, // Default is Step 1 email: '', username: '', password: '', } // Bind the submission to handleChange() this.handleChange = this.handleChange.bind(this) } // Use the submitted data to set the state handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } // Trigger an alert on form submission handleSubmit = (event) => { event.preventDefault() const { email, username, password } = this.state alert(`Your registration detail: \n Email: ${email} \n Username: ${username} \n Password: ${password}`) } // Render UI will go here... }

OK, that’s the baseline functionality we’re looking for. Next, we want to create the shell UI for the actual form add call the child components in it, including the required state props that will be passed from <MasterForm/> via handleChange().

render() { return ( <React.Fragment> <h1>A Wizard Form!</h1> <p>Step {this.state.currentStep} </p> <form onSubmit={this.handleSubmit}> // Render the form steps and pass in the required props <Step1 currentStep={this.state.currentStep} handleChange={this.handleChange} email={this.state.email} /> <Step2 currentStep={this.state.currentStep} handleChange={this.handleChange} username={this.state.username} /> <Step3 currentStep={this.state.currentStep} handleChange={this.handleChange} password={this.state.password} /> </form> </React.Fragment> ) } One step at a time

So far, we’ve allowed users to fill the form fields, but we've provided no actual way to proceed to the next step or head back to the previous one. That calls for next and previous functions that check if the current step has a previous or next step; and if it does, push the currentStep prop up or down accordingly.

class MasterForm extends Component { constructor(props) { super(props) // Bind new functions for next and previous this._next = this._next.bind(this) this._prev = this._prev.bind(this) } // Test current step with ternary // _next and _previous functions will be called on button click _next() { let currentStep = this.state.currentStep // If the current step is 1 or 2, then add one on "next" button click currentStep = currentStep >= 2? 3: currentStep + 1 this.setState({ currentStep: currentStep }) } _prev() { let currentStep = this.state.currentStep // If the current step is 2 or 3, then subtract one on "previous" button click currentStep = currentStep <= 1? 1: currentStep - 1 this.setState({ currentStep: currentStep }) } }

We’ll use a get function that will check whether the current step is 1 or 3. This is because we have three-step form. Of course, we can change these checks as more steps are added to the form. We also want to display the next and previous buttons only if there actually are next and previous steps to navigate to, respectively.

// The "next" and "previous" button functions get previousButton(){ let currentStep = this.state.currentStep; // If the current step is not 1, then render the "previous" button if(currentStep !==1){ return ( <button className="btn btn-secondary" type="button" onClick={this._prev}> Previous </button> ) } // ...else return nothing return null; } get nextButton(){ let currentStep = this.state.currentStep; // If the current step is not 3, then render the "next" button if(currentStep <3){ return ( <button className="btn btn-primary float-right" type="button" onClick={this._next}> Next </button> ) } // ...else render nothing return null; }

All that’s left is to render those buttons:

// Render "next" and "previous" buttons render(){ return( <form onSubmit={this.handleSubmit}> {/* ... other codes */} {this.previousButton} {this.nextButton} </form> ) } Congrats, you’re a form wizard! &#x1f9d9;

That was the last step in this multi-step tutorial on multi-step forms. Whoa, how meta! While we didn’t go deep into styling, hopefully this gives you a solid overview of how to go about making complex forms less… complex!

Here’s that final demo again so you can see all the code in it’s full and glorious context:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

React was made for this sort of thing considering it makes use of states, property changes, reusable components and such. I know that React may seem like a high barrier to entry for some folks, but I’ve written a book that makes it a much lower hurdle. I hope you check it out!

The post The Magic of React-Based Multi-Step Forms appeared first on CSS-Tricks.

The #StateOfCSS 2019 Survey

Fri, 02/15/2019 - 5:19am

You know about the State of JavaScript survey, where thousands upon thousands of developers were surveyed about all-things-JS, from frameworks to testing and many other things in between? Well, Sacha Greif has launched one focused entirely on CSS.

This is super timely given a lot of the content we and other sites have been posting lately centered around learning, complexity, changing roles, and more. Sacha captures it nicely:

This is especially interesting since it comes at a time where many are talking about a “Great Divide” between the “front” of the front-end (HTML, CSS) and the “back” of the front-end (JavaScript and its many frameworks and libraries). [...] [T]he survey will be a great chance to take a snapshot of the community as it currently exists, and see how this evolves over the next couple years.

Sounds like a good goal. Let's help by putting some responses in there!

Take Survey

Direct Link to ArticlePermalink

The post The #StateOfCSS 2019 Survey appeared first on CSS-Tricks.

Getting to Grips with the Airtable API

Thu, 02/14/2019 - 5:31am

The Airtable web app is pretty neat. You can use it like a spreadsheet but it’s useful for all sorts of other things too. The neatest thing about it for me is that it has an API so that you can treat it like a database.

I’ve been thinking about making weekly notes for the different teams I work with at Gusto to read about what the design systems team is working on, things we've fixed, and any bugs we've encountered during that might impact other designers and engineers across our organization. I’ve spent a couple of hours thinking about how we might use Airtable to collect a whole bunch of data and then use its API to extract that info and show it in a web app.

Here’s an example of what we’ll end up building, which is basically a React web app that’s using Airtable as a nifty sorta CMS:

To get started, we have to head on over to the command line and run the following (but first make sure npm is installed):

npx create-react-app airtable-test

This will create a new directory called airtable-test which is where we’ll be making our little React app. If we run yarn start in the command line after that’s finished installing, then we’ll see the default page for the project:

And, if we open up src/App.js in that airtable-test directory, we can see how this page is being rendered with React:

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit src/App.js and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </header> </div> ); } } export default App;

Now that we have React up and running, we can go ahead and install airtable in the command line which will let us interact with the Airtable API:

npm i airtable

Once we’ve done that, we’ll need to create an Airtable account and create a project. We should wind up with something like this spreadsheet:

Now we can then head to airtable.com/api and select our project so that is serves as data we're pulling from. In this case, I selected “Design Systems Projects” which you can see right at the bottom here:

This will send us to a handy docs website that gives us an incredibly easy to read API for our specific project! Scrolling down we’ll find our API key which we’ll need to access this data as well as a ton of examples that we can use to manipulate the data we get back:

Let's head back to App.js in our airtable-test directory, delete all the code in that file, and replace it with the following:

import React, { Component } from 'react'; import Airtable from 'airtable'; const base = new Airtable({ apiKey: 'XXXXXXXXXXX' }).base('XXXXXXXXXXX');

Make sure to replace those Xs with the details that you can see in that Airtable API doc we just opened. But now that we’ve done all the setup, we can finally get around to creating our interface by calling data from our spreadsheet.

In App.js we can start to construct the App component:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } render() { return { <div className="App">Hello</div> } } } }

All this will do for now is setup the app’s state and then render “Hello” on the page. Next up, we’ll be add each record from Airtable to that state.

First thing that’s important to note below: in componentDidMount() we’ll be selecting Updates which is just a way of telling Airtable that we want the spreadsheet called Updates. Make sure that this name is the same name as the spreadsheet. We’ll also be looping through all the records, or rows, of our table in that function too:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); console.log(records); fetchNextPage(); } ); } render() { return ( <div className="App"> <div>Hello</div> </div> ); } }

fetchNextPage() is the Airtable API’s way of giving us the next record in our spreadsheet and it’s neat that it will keep going until there are no more records. Again, we’re not doing anything with that data yet; we only want to make sure everything is working correctly at this point.

Open up the console in DevTools and we should see something like this:

Array(4) [ {…}, {…}, {…}, {…} ]

And if we dive through each of the objects in this array, then we should find all the data from the spreadsheet! Doing this bit always feels like magic to me.

Anyway, next up we can update our render() function like so:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{record.fields['Date']}</h2> {record.fields['UI Kit']} {record.fields['Component Library']} </div> ) ) : ( <p>Loading...</p> )} </div> </div> ); }

We’re going to be looping through the state that we setup earlier and then rendering the record.fields[] for each column in our spreadsheet. We have a Date, UI Kit, and Component Library column, and once we’ve updated our App.js with the code above, we should see all the content from our spreadsheet!

It’s like magic! But why does this data look so weird? Well, it’s because I wanted to write Markdown in each cell, so now we’ll need to use a parser to convert that data into good ol’ fashioned HTML. First, we need to head back to the command line though:

npm i showdown

showdown will help us parse all that Markdown we’ve written in our Airtable spreadsheet. After installing it, we only need to import it at the top of our App.js file, like this:

import showdown from 'showdown'; const markdownConverter = new showdown.Converter();

After the componentDidMount() function, we can create another function that will create our HTML using showdown:

createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) }

It’s a little iffy, but it makes me feel like the code is a bit tidier this way. Now we can update our render() function:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); }

We’re doing a couple of new things here: we’re using dangerouslySetInnerHTML in each div which, in turn, uses our createHTML function to convert the data from each column (specifically, the UI Kit and Component Library columns). We’re also converting the dates of each row into headings to make things a bit easier to read.

And with that we’re pretty much done! Here’s the final App.js:

import React, { Component } from 'react'; import Airtable from 'airtable'; import showdown from 'showdown'; const markdownConverter = new showdown.Converter(); const base = new Airtable({ apiKey: 'xxxxxxx' }).base('xxxxxxx'); class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); fetchNextPage(); } ); } createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) } render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); } } export default App;

There’s still a ton of updates we could make to improve things. I took a first pass at styling, but we probably want to do things like improve the date format and maybe have some kind of indication as to which updates refer to which rows in the spreadsheet. Maybe we could even toggle showing which information to show depending on whether you’re a designer or engineer.

Anyway! I think this is a good start to getting to grips with the Airtable API and I’d love to hear about how you use it in the comments below.

The post Getting to Grips with the Airtable API appeared first on CSS-Tricks.

Use monday.com to manage and share projects all in one place

Thu, 02/14/2019 - 5:29am

(This is a sponsored post.)

We've talked quite a bit about project management and workflows around here at CSS-Tricks, not because it's the core of what we do as designers and developers, but because we all play a role in it as part of a team and because it impacts the quality of our work at the end of the day.

That's why having a good system in place is such a benefit both to us and to teams as a whole. Where can you find a system like that? You might want to start by looking at monday.com. Yes, it's a project management tool but it actually goes way beyond that. Where some other platforms out there stop at task lists, calendars, and milestones, monday.com does those plus team collaboration.

If you've ever felt out of the loop on a project, had a surprise change in scope, or even been curious what other folks on your team have been up to, that's where monday.com really shines. It's people-centric, giving you and others insight into activity across an entire project through news feeds, messaging, shared assets, clearly defined user roles, among any other things. It's what a healthy, transparent, and collaborative team environment looks like.

We've only scratched the surface here, but lucky for you, there's a free 14-day trial to check out everything that monday.com has to offer. Go for it!

Try it Now

Direct Link to ArticlePermalink

The post Use monday.com to manage and share projects all in one place appeared first on CSS-Tricks.

The Smart Ways to Correct Mistakes in Git

Wed, 02/13/2019 - 1:09pm

The world of software development offers an infinite amount of ways to mess up: deleting the wrong things, coding into dead ends, littering commit messages with typos, are a mere few of the plentitude.
??
??Fortunately, however, we have a wonderful safety net under our feet in the form of Git when we’re working with version control. Not that you and I need a safety net, of course, because we never make mistakes, right? Sure, sure. But for the benefit of everyone else, let's take a tour of some of the "undo" tools in Git that can save us from ourselves.
??
??
??
??

Fixing the last commit

??
??Messing up a commit is all too easy. Classic case in point: making a typo in a commit message. Another? Forgetting to add a change to the staging area. And in many cases, we instantly realize our mistake — right after hitting the Enter key, naturally.
??
??Luckily, Git makes it ridiculously easy to fix the very last commit. Let's say we had just hit Enter on the following command:

??

git commit -m "Massage full of typohs"

??
??And (as if this orthographic mess wasn't bad enough) let's say we also forgot to add another changed file to the staging area. We can correct both of our mistakes with the following two commands:
??

git add forgotten-changes.js ??git commit --amend -m "A sensible message"

??
??The magic ingredient is the --amend? flag: when using it on a commit, Git will correct the very last commit — with any staged changes and the new message.
??
??A short word of warning, though: only use --amend? on commits that haven't been pushed to a remote repository, yet. The reason is that Git replaces the original, bad commit with the amended version. Afterwards, it looks as if the original commit never happened. Yeah, that’s good for concealing mistakes, but only if we haven't already published this mistake on the remote server.
????
??

Undoing local changes

??
??Everyone’s had days like this: spend all morning hacking away, only to admit to yourself that the last few hours were a waste of time. Gotta start over and undo much (or all) of that work.
??
??But this is one of the reasons for using Git in the first place — to be able to try out things without the fear that we might break something.
??
??Let's take stock in an example situation:
??

git status ?? modified: about.html ?? deleted: imprint.html ?? modified: index.html

??
??Now, let's assume that this is one of the wasted hacking days described above. We ought to have kept our hands off of about.html and not deleted imprint.html. What we now want is to discard our current changes in these files — while keeping the brilliant work done in index.html. ??The git checkout? command can help in this case. Instead, we’ve gotta get more specific with which files to check out, like this:

??

git checkout HEAD about.html imprint.html

??This command restores both about.html and imprint.html to their last committed states. Phew, we got away from a black eye!
??
??We could take this one step further and discard specific individual lines in a changed file instead of tossing out the entire thing! I’ll admit, it’s rather complicated to make it happen on the command line, but using a desktop Git client like Tower is a great way to go about it:

??
??For those really bad days, we might want to bring out the big guns in the form of:
??
??

git reset --hard HEAD

??
??While we only restored specific files with checkout?, this command resets our whole working copy. In other words, reset? restores the complete project at its last committed state. ??Similar to --amend?, there's something to keep in mind when using checkout? and reset?: discarding local changes with these commands cannot be undone! They have never been committed to the repository, so it's only logical that they cannot be restored. Better be sure that you really want to get rid of them because there’s no turning back!
??
??

Undoing and reverting an older commit

??
??In many cases, we only realize a mistake much later, after it has long been committed to the repository.

??How can we get rid of that one bad commit? Well, the answer is that we shouldn't… at least in most cases. Even when "undoing" things, Git normally doesn't actually delete data. It corrects it by adding new data. Let's see how this works using our "bad guy" example:
??
??

git revert 2b504bee

??
??By using git revert? on that bad commit, we haven't deleted anything. Quite the contrary:

??Git automatically created a new commit with changes that reverts the effects of the "bad" commit. So, really, if we started with three commits and were trying to correct the middle one, now we have four total commits, with a new one added that corrects the one we targeted with revert?.
????
??

Restoring a previous version of a project

??
??A different use case is when we want to restore a previous version of our project. Instead of simply undoing or reverting a specific revision somewhere in our commit history, we might really want to turn back time and return to a specific revision.
??
??In the following example scenario, we would declare all the commits that came after "C2" as unwanted. What we want is to return to the state of commit "C2" and forget everything that came after it in the process:

??The command that's necessary is already (at least partly) familiar to you based on what we’ve already covered:
??
??

git reset --hard 2b504bee

??
??This tells git reset? the SHA-1 hash of the commit we want to return to. Commits C3 and C4 then disappear from the project's history.
??
??If you're working in a Git client, like Tower, both git revert? and git reset are available from the contextual menu of a commit item:

??

??Deleting commits, restoring deleted branches, dealing with conflicts, etc. etc. etc.

??
??Of course, there are many other ways to mess up things in a software project. But luckily, Git also offers many more tools for undoing the mess.
??
??Have a look at the "First Aid Kit for Git" project that I and other folks on the Tower team have created if you want to learn more about the scenarios we covered in this post, or about other topics, like how to move commits between branches, delete old commits, restore deleted branches or gracefully deal with merge conflicts. It’s a totally free guide that includes 17 videos and a handy cheat sheet you can download and keep next to your machine.

??In the meantime, happy undoing!

The post The Smart Ways to Correct Mistakes in Git appeared first on CSS-Tricks.

“the closest thing web standards have to a golden rule”

Wed, 02/13/2019 - 1:02pm

The internet's own Mat Marquis plucks this choice quote from the HTML Design Principals spec:

In case of conflict, consider users over authors over implementors over specifiers over theoretical purity.

And then he applies the idea to putting images on websites in 2019.

Direct Link to ArticlePermalink

The post “the closest thing web standards have to a golden rule” appeared first on CSS-Tricks.

??Avoiding those dang cannot read property of undefined errors

Wed, 02/13/2019 - 6:30am

????Uncaught TypeError: Cannot read property 'foo' of undefined.? The dreaded error we all hit at some point in JavaScript development. Could be an empty state from an API that returns differently than you expected. Could be something else. We don’t know because the error itself is so general and broad.

??I recently had an issue where certain environment variables weren't being pulled in for one reason or another, causing all sorts of funkiness with that error staring me in the face. Whatever the cause, it can be a disastrous error if it’s left unaccounted for, so how can we prevent it in the first place?

??Let’s figure it out.

??Utility library

??If you are already using a utility library in your project, there is a good chance that it includes a function for preventing this error. _.get? in lodash? (docs) or R.path in Ramda? (docs) allow accessing the object safely.
??
??If you are already using a utility library, this is likely the simplest solution. If you are not using a utility library, read on!

??

Short-circuiting with &&

????One interesting fact about logical operators in JavaScript is that they don't always return a boolean. According to the spec, "the value produced by a &&? or ||? operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.”
??
????In the case of the &&? operator, the first expression will be used if it a "falsy" value. Otherwise, the second expression will be used. This means that the expression 0 && 1? will be evaluated as 0? (a falsy value), and the expression 2 && 3? will be evaluated as 3?. If multiple &&? expressions are chained together, they will evaluate to either the first falsy value or the last value. For example, 1 && 2 && 3 && null && 4? will evaluate to null?, and 1 && 2 && 3? will evaluate to 3?.

????How is this useful for safely accessing nested object properties? Logical operators in JavaScript will "short-circuit." In this case of &&?, this means that the expression will cease moving forward after it reaches its first falsy value.

????

??const foo = false && destroyAllHumans(); ??console.log(foo); // false, and humanity is safe

??In this example, destroyAllHumans is never called because the &&? operand stopped all evaluation after false?.

??This can be used to safely access nested properties.

??

??const meals = { ?? breakfast: null, // I skipped the most important meal of the day! :( ?? lunch: { ?? protein: 'Chicken', ?? greens: 'Spinach', ?? }, ?? dinner: { ?? protein: 'Soy', ?? greens: 'Kale', ?? }, ??}; ?? ??const breakfastProtein = meals.breakfast && meals.breakfast.protein; // null ??const lunchProtein = meals.lunch && meals.lunch.protein; // 'Chicken'

??Aside from its simplicity, one of the main advantages of this approach is its brevity when dealing with small chains. However, when accessing deeper objects, this can be quite verbose.

??

const favorites = { ?? video: { ?? movies: ['Casablanca', 'Citizen Kane', 'Gone With The Wind'], ?? shows: ['The Simpsons', 'Arrested Development'], ?? vlogs: null, ?? }, ?? audio: { ?? podcasts: ['Shop Talk Show', 'CodePen Radio'], ?? audiobooks: null, ?? }, ?? reading: null, // Just kidding -- I love to read ??}; ?? ??const favoriteMovie = favorites.video && favorites.video.movies && favorites.video.movies[0]; ??// Casablanca ??const favoriteVlog = favorites.video && favorites.video.vlogs && favorites.video.vlogs[0]; ??// null

??The more deeply nested an object is, the more unwieldy it gets.

??
??

The “Maybe Monad”

??Oliver Steele came up with this method and goes through it in much more detail in his blog post, "Monads on the Cheap I: The Maybe Monad." I will attempt to give a brief explanation here.

??

const favoriteBook = ((favorites.reading||{}).books||[])[0]; // undefined ??const favoriteAudiobook = ((favorites.audio||{}).audiobooks||[])[0]; // undefined ??const favoritePodcast = ((favorites.audio||{}).podcasts||[])[0]; // 'Shop Talk Show'

??Similar to the short-circuit example above, this method works by checking if a value is falsy. If it is, it will attempt to access the next property on an empty object. In the example above, favorites.reading? is null?, so the books? property is being accessed from an empty object. This will result in an undefined?, so the 0? will likewise be accessed from an empty array.

??The advantage of this method over the &&? method is that it avoids repetition of property names. On deeper objects, this can be quite a significant advantage. The primary disadvantage would be readability — it is not a common pattern, and may take a reader a moment to parse out how it is working.?

??

??try/catch

????try...catch? statements in JavaScript allow another method for safely accessing properties.

??

try { ?? console.log(favorites.reading.magazines[0]); ??} catch (error) { ?? console.log("No magazines have been favorited."); ??}

??Unfortunately, in JavaScript, try...catch? statements are not expressions. They do not evaluate to a value as they do in some languages. This prevents a concise try? statement as a way of setting a variable.

??One option is to use a let? variable that is defined in the block above the try...catch?.

??

let favoriteMagazine; ??try { ?? favoriteMagazine = favorites.reading.magazines[0]; ??} catch (error) { ?? favoriteMagazine = null; /* any default can be used */ ??};

??Although it’s verbose, this works for setting a single variable (that is, if the mutable variable doesn't scare you off). However, issues can arise if they’re done in bulk.

??

let favoriteMagazine, favoriteMovie, favoriteShow; ??try { ?? favoriteMovie = favorites.video.movies[0]; ?? favoriteShow = favorites.video.shows[0]; ?? favoriteMagazine = favorites.reading.magazines[0]; ??} catch (error) { ?? favoriteMagazine = null; ?? favoriteMovie = null; ?? favoriteShow = null; ??}; ?? ??console.log(favoriteMovie); // null ??console.log(favoriteShow); // null ??console.log(favoriteMagazine); // null

??If any of the attempts to access the property fails, this will cause all of them to fall back into their defaults.

??An alternative is to wrap the try...catch? in a reusable utility function.

??

const tryFn = (fn, fallback = null) => { ?? try { ?? return fn(); ?? } catch (error) { ?? return fallback; ?? } ??} ?? ??const favoriteBook = tryFn(() => favorites.reading.book[0]); // null ??const favoriteMovie = tryFn(() => favorites.video.movies[0]); // "Casablanca"

??By wrapping the access to the object in a function, you can delay the "unsafe" code and pass it into a try...catch?.

??A major advantage of this method is how natural it is to access the property. As long as properties are wrapped in a function, they are safely accessed. A default value can also be specified in the case of a non-existent path.

??Merge with a default object

??
By merging an object with a similarly shaped object of "defaults," we can ensure that the path that we are trying to access is safe.
??
??

const defaults = { ?? position: "static", ?? background: "transparent", ?? border: "none", ??}; ?? ??const settings = { ?? border: "1px solid blue", ??}; ?? ??const merged = { ...defaults, ...settings }; ?? ??console.log(merged); ??/* ?? { ?? position: "static", ?? background: "transparent", ?? border: "1px solid blue" ?? } ??*/

??
??Careful, though, because the entire nested object can be overwritten rather than a single property.
??
??

const defaults = { ?? font: { ?? family: "Helvetica", ?? size: "12px", ?? style: "normal", ?? }, ?? color: "black", ??}; ?? ??const settings = { ?? font: { ?? size: "16px", ?? } ??}; ?? ??const merged = { ?? ...defaults, ?? ...settings, ??}; ?? ??console.log(merged.font.size); // "16px" ??console.log(merged.font.style); // undefined

??Oh no! To fix this, we'll need to similarly copy each of the nested objects.

??

const merged = { ?? ...defaults, ?? ...settings, ?? font: { ?? ...defaults.font, ?? ...settings.font, ?? }, ??}; ?? ??console.log(merged.font.size); // "16px" ??console.log(merged.font.style); // "normal"

??Much better!

??This pattern is common with plugins or components that accept a large settings object with included defaults.

??A bonus about this approach is that, by writing a default object, we’re including documentation on how an object should look. Unfortunately, depending on the size and shape of the data, the "merging" can be littered with copying each nested object.

???

The future: optional chaining

??There is currently a TC39 proposal for a feature called "optional chaining." This new operator would look like this:

??console.log(favorites?.video?.shows[0]); // 'The Simpsons' ??console.log(favorites?.audio?.audiobooks[0]); // undefined

??The ?.? operator works by short-circuiting: if the left-hand side of the ?.? operator evaluates to null? or undefined?, the entire expression will evaluate to undefined? and the right-hand side will remain unevaluated.

??To have a custom default, we can use the ||? operator in the case of an undefined.

??

console.log(favorites?.audio?.audiobooks[0] || "The Hobbit");

??

Which method should you use?

??The answer, as you might have guessed, is that age-old answer… "it depends." If the optional chaining operator has been added to the language and has the necessary browser support, it is likely the best option. If you are not from the future, however, there are more considerations to take into account. Are you using a utility library? How deeply nested is your object? Do you need to specify defaults? Different cases may warrant a different approach.

The post ??Avoiding those dang cannot read property of undefined errors appeared first on CSS-Tricks.

A Site for Front-End Development Conferences (Built with 11ty on Netlify)

Tue, 02/12/2019 - 12:48pm

I built a new little site! It's a site for listing upcoming conferences in the world of front-end web design and development. In years past (like 2017), Sarah Drasner took up this daunting job. We used a form for new conference submissions, but it was still a rather manual task of basically manually editing a blog post. I wanted to keep doing this, as I think it's valuable to have a simple reference page for conferences in our niche slice of the web, but I wanted the site to be able to live on year after year with lower maintenance-related technical debt.

So this is what I did!

I wanted to get it on GitHub.

So I put it there. Part of the beauty of GitHub is that it opens up the idea of collaboration through pull requests to really anyone in the world. You need to have a GitHub account, but that's free, and you need to understand Git at least on some minor level (which is a barrier that I'd like to resolve in time), but it invites more collaboration than something like just asking people to email you content and ideas.

I wanted the content in Markdown in the Repo.

The Front Matter format, which is Markdown with some data the the top, is such a useful and approachable format. You need almost zero knowledge, not even HTML, to be able to create/edit a file like this:

Having the actual conference data in the repo means that pull requests aren't just for design or features; more commonly, they will be for actual conference data. The work of making this site full of all the best conferences is the work of all of us, not just one of us.

At the time of this writing there have already been 30 closed pull requests.

I used 11ty to build the site.

11ty is almost fascinatingly simple. It looks in one directory for what it needs to process or move to another directory. It supports my favorite templating system out of the box: Nunjucks. Plus front matter Markdown like I mentioned above.

I was able to essentially design a card that displays the data we get from the Markdown files, and then build the homepage of the site by looping over those Markdown files and applying the templated card.

11ty is based on Node.js, so while I did have some learning-curve moments, it was comfortable for me to work in. There definitely is configuration for doing the things I wanted to be doing. For example, this is how I had to make a "collection" of conferences in order to loop over them:

config.addCollection("conferences", function(collection) { let allConferences = collection.getFilteredByGlob("site/conferences/*.md"); let futureConferences = allConferences.filter(conf => { return conf.data.date >= new Date(); }); return futureConferences; }); The site is hosted on Netlify.

One reason to use Netlify here is that it's incredibly easy. I made a site site in Netlify by connecting it to the GitHub repo. I told it how to build the site (it's a single command: eleventy) and where the built site files are (dist), and that's it. In fact, that's even part of the repo:

Now whenever I push to the master branch (or accept a pull request into master), the site automatically rebuilds and deploys. Just takes seconds. It's really amazing.

Better, for each pull request, Netlify makes sure everything is in order first:

My favorite is the deploy preview. It gives you an (obscure) URL that will literally last forever (immutable) and that serves as a look at the built version of this site with that pull request.

So, not only is it extremely easy to use Netlify, but I get a bunch of stuff for free, like the fact that the site is smokin' fast on their CDNs and such.

I'm also excited that I've barely tapped into Netlify's features here, so there is a lot of stuff I can dig into over time. And I intend to!

I use Zapier to re-build the site every day.

There is a bit of a time-sensitive nature to this site. The point of this site is to reference it for upcoming conferences. It's less interesting to see past conferences (although maybe we can have a browse-able archive in the future). I like the idea of ripping off past conferences for the homepage. If this was PHP (or whatever), we could do that at runtime, but this is a static site (on purpose). Doing something like this at build time is no big deal (see that code snippet above that only returns conferences past today's date). But we can't just waiting around for pull requests to re-build the site, nor do I want to make it a manual thing I need to do every day.

Fortunately, this is easy as pie with Zapier:

Phil Hawksworth took this to the extreme once and built a clock website that rebuilds every minute.

This site wasn't just an experiment. I'd like to keep it going! If you're part of running a conference, I'm quite sure it doesn't hurt to add it to add yours, just so long as it has an enforcable and actionable Code of Conduct, and is within the world of front-end web design and development.

The post A Site for Front-End Development Conferences (Built with 11ty on Netlify) appeared first on CSS-Tricks.

Quick! What’s the Difference Between Flexbox and Grid?

Tue, 02/12/2019 - 12:22pm

Let's go rapid fire and try to answer this question with quick points rather than long explanations. There are a lot of similarities between flexbox and grid, starting with the fact that they are used for layout and much more powerful than any layout technique that came before them. They can stretch and shrink, they can center things, they can re-order things, they can align things... There are plenty of layout situations in which you could use either one to do what we need to do, and plenty of situations where one is more well-suited than the other. Let's focus on the differences rather than the similarities:

Flexbox can optionally wrap. If we allow a flex container to wrap, they will wrap down onto another row when the flex items fill a row. Where they line up on the next row is independent of what happenned on the first row, allowing for a masonry-like look.

Grid can also optionally wrap (if we allow auto filling) in the sense that items can fill a row and move to the new row (or auto place themselves), but as they do, they will fall along the same grid lines all the other elements do.

Flexbox on top, Grid on bottom

You could think of flexbox as "one dimensional." While flexbox can make rows and columns in the sense that it allows elements to wrap, there's no way to declaratively control where elements end up since the elements merely push along a single axis and then wrap or not wrap accordingly. They do as they do, if you will, along a one-dimensional plane and it's because of that single dimension that we can optionally do things, like align elements along a baseline — which is something grid is unable to do.

.parent { display: flex; flex-flow: row wrap; /* OK elements, go as far as you can on one line, then wrap as you see fit */ }

You could think of grid as "two dimensional" in that we can (if we want to) declare the sizing of rows and columns and then explicitly place things into both rows and columns as we choose.

.parent { display: grid; grid-template-columns: 1fr 3fr 1fr; /* Three columns, one three times as wide as the others */ grid-template-rows: 200px auto 100px; /* Three rows, two with explicit widths */ grid-template-areas: "header header header" ". main sidebar" "footer . ."; } /* Now, we can explicitly place items in the defined rows and columns. */ .child-1 { grid-area: header; } .child-2 { grid-area: main; } .child-3 { grid-area: sidebar; } .child-4 { grid-area: footer; } Flexbox on top, Grid on bottom

I'm not the world's biggest fan of the "1D" vs. "2D" differentiation of grid vs. flexbox, only because I find most of my day-to-day usage of grid is "1D" and it's great for that. I wouldn't want someone to think they have to use flexbox and not grid because grid is only when you need 2D. It is a strong distinction though that 2D layout is possible with grid though in ways it is not in flexbox.

Grid is mostly defined on the parent element. In flexbox, most of the layout (beyond the very basics) happen on the children.

/* The flex children do most of the work */ .flexbox { display: flex; > div { &:nth-child(1) { // logo flex: 0 0 100px; } &:nth-child(2) { // search flex: 1; max-width: 500px; } &:nth-child(3) { // avatar flex: 0 0 50px; margin-left: auto; } } } /* The grid parent does most of the work */ .grid { display: grid; grid-template-columns: 1fr auto minmax(100px, 1fr) 1fr; grid-template-rows: 100px repeat(3, auto) 100px; grid-gap: 10px; }

Grid is better at overlapping. Getting elements to overlap in flexbox requires looking at traditional stuff, like negative margins, transforms, or absolute positioning in order to break out of the flex behavior. With grid, we can place items on overlapping grid lines, or even right within the same exact grid cells.

Flexbox on top, Grid on bottom

Grid is sturdier. While the flexing of flexbox is sometimes its strength, the way a flex item is sized gets rather complicated. It's a combination of width, min-width, max-width, flex-basis, flex-grow, and flex-shrink, not to mention the content inside and things like white-space, as well as the other items in the same row. Grid has interesting space-occupying features, like fractional units, and the ability for content to break grids, though, generally speaking, we're setting up grid lines and placing items within them that plop right into place.

Flexbox can push things away. It's a rather unique feature of flexbox that you can, for example, put margin-right: auto; on an element and, if there is room, that element will push everything else as far away as it can go can.

Here are some of my favorite tweets on the subject:

flexbox looks like it does what you want
but grid is usually what you want

— Old Guard Rupert (@davatron5000) January 25, 2019

Grid makes actual columns and rows. Content will line up from one to the other, as you ask it to. Flexbox doesn’t. Not only in the second dimension (which is easiest to talk about), but also in the first dimension. Flexbox isn’t for most of the things we’ve been using it for.

— Jen Simmons (@jensimmons) January 26, 2019

How about this:#Flexbox is for alignment. #CSSGrid is for layout.

This is almost always how I wind up using them. It allows them to preserve their relationships to one another. It also allows each to be used for its strength, even though each can do the other thing.

— Brian Haferkamp (@BrianHaferkamp) January 25, 2019

If you start constraining all your flex items with a width, then more often than not it will be easier to use grid.

— Rachel Andrew (@rachelandrew) January 25, 2019

Here's another difference, but it's not a favorite way of describing them, just fun dumb knowledge:

flexbox takes 2 passes to finish
grid takes 3

so one could say, grid is slow and flexbox is fast lol

— Adam Argyle (@argyleink) January 25, 2019

For me Grid is there to great full layout..grids...with more control over how the whole are/page comes together, whereas flexbox helps me to position and align (whether it’s in a grid or not).

For me it’s about purpose.

— Mandy Michael (@Mandy_Kerr) January 25, 2019

The distinction between the two is often blurry, especially now that we also have `gap` for flexbox. Grid is best suited for a few specific use cases (2D obviously, but also things like overlapping elements) while flexbox usually shines in simpler yet common layout requirements.

— Benjamin De Cock (@bdc) January 25, 2019

Use grid when you already have the layout structure in mind, and flex when you just want everything to fit. Layout first vs content first.

— Beverly (@aszenitha) January 25, 2019

The post Quick! What’s the Difference Between Flexbox and Grid? appeared first on CSS-Tricks.

©2003 - Present Akamai Design & Development.