Tech News

Using Trello as a Super Simple CMS

Css Tricks - Mon, 07/27/2020 - 4:37am

Sometimes our sites need a little sprinkling of content management. Not always. Not a lot. But a bit. The CMS market is thriving with affordable, approachable products, so we’re not short of options. Thankfully, it is a very different world to the one that used to force companies to splash out a ga-jillionty-one dollars (not an exact cost: I rounded to the nearest bazillion) for an all-singing, all-dancing, all-integrating, all-personalizing, big-enterprise-certified™ CMS platform.

Sometimes, though, it’s nice to use a really simple tool that anyone updating content on the site is already familiar with, rather than getting to grips with a new CMS. 

I like Trello a lot for managing ideas and tasks. And it has an API. Why not use it as a content source for a web site? I mean, hey, if we can do it with Google Sheets, then what’s to stop us from trying other things?

Hello, Trello

Here’s a simple site to explore. It gets its content from this Trello board and that content is displayed in sections. Each section is populated by the title and description fields of a card in our Trello board.

Trello uses Markdown, which comes in handy here. Anyone editing content in a Trello card is able to apply basic text formatting and have the same Markdown flow into the site and transformed into HTML by a build process.

Building blocks

I’m a big fan of this model of running a build which pulls content from various feeds and sources, and then mashes them together with a template to generate the HTML of a website. It decouples the presentation from the management of the content (which is where the term “decoupled” comes from in popular modern CMS products). And it means that we are free to craft the website just the way we want with all of the wizzy tricks and techniques we’ve learned here on CSS-Tricks.

Since we pull in the content at build time, we don’t need to worry about the usage quotas or the performance of our data sources if our sites get popular and bring in loads of traffic. And why wouldn’t they? Look how pretty we made them!

I wanna play!

Fine. You can grab a copy of this site’s code and tinker around to your heart’s content. This version includes information on how to create your own Trello board and use it as the source for content for the build.

If you want to walk through how this works first rather than diving right into it yourself, read on.

Discovering the API

Trello has a well-documented API and set of developer resources. There is also a handy Node module to simplify the task of authenticating and interacting with the API. But you can also explore the API by tinkering with the URLs when you are exploring your Trello boards. 

For example, the URL for the Trello board above is:

https://trello.com/b/Zzc0USwZ/hellotrello

If we add .json to that URL, Trello shows us the content represented as JSON. Take a look.

We can use this technique to inspect the underlying data throughout Trello. Here is the URL for one card in particular:

https://trello.com/c/YVxlSEzy/4-sections-from-cards

If we use this little trick and add .json to the URL we’ll see the data which describes that card

We’ll find interesting things — unique IDs for the board, the list, and the card. We can see the card’s content, and lots of metadata.

I love doing this! Look at all the lovely data! How shall we use it?

Deciding how to use a board

For this example, let’s assume that we have a site with just one page of manageable content. A list or column in our board would be ideal for controlling the sections on that page. An editor could give them titles and content, and drag them around into the order they want.

We’ll need the ID of the list so that we can access it via the API. Luckily, we’ve already seen how to discover that — take a look at the data for any of the cards in the list in question. Each one has an idBoard property. Bingo!

Generating the site

The plan is to fetch the data from Trello and apply it to some templates to populate our site. Most static site generators (SSG) would do the job. That’s what they are good at. I’ll use Eleventy because I think it has the simplest concepts to understand. Plus, it is very efficient at getting data and generating clean HTML with Nunjucks (a popular templating language).

We’ll want to be able to use an expression lin our template that outputs a section element for each item found in a JavaScript object called trello:

<!-- index.njk --> {% for card in trello %} <section> <h2>{{ card.name }}</h2> <div> {% markdown %} {{- card.desc | safe }} {% endmarkdown %} </div> </section> {% endfor %} Fetching the data for the build

A popular technique with Jamstack sites like this is to run a build with Gulp, Grunt or [insert latest new build script hotness here] which goes and fetches data from various APIs and feeds, stashes the data in a suitable format for the SSG, and then runs the SSG to generate the HTML. This works rather nicely.

Eleventy simplifies things here by supporting the execution of JavaScript in its data files. In other words, rather than only leveraging data stored as JSON or YAML, it can use whatever gets returned by JavaScript, opening the door to making requests directly to APIs when the Eleventy build runs. We won’t need a separate build step to go off to fetch data first. Eleventy will do it for us.

Let’s use that to get the data for our trello object in the templates.

We could use the Trello Node client to query the API, but as it turns out all the data we want is right there in the JSON for the board. Everything! In one request! We can just fetch it in one go!

// trello.js module.exports = () => { const TRELLO_JSON_URL='https://trello.com/b/Zzc0USwZ/hellotrello.json'; // Use node-fetch to get the JSON data about this board const fetch = require('node-fetch'); return fetch(TRELLO_JSON_URL) .then(res => res.json()) .then(json => console.log(json)); };

However, we don’t want to show all the data from that board. It includes cards on other lists, cards which have been closed and deleted, and so on. But we can filter the cards to only include the ones of interest thanks to JavaScript’s filter method.

// trello.js module.exports = () => { const TRELLO_JSON_URL='https://trello.com/b/Zzc0USwZ/hellotrello.json' const TRELLO_LIST_ID='5e98325d6d6bd120f2b7395f', // Use node-fetch to get the JSON data about this board const fetch = require('node-fetch'); return fetch(TRELLO_JSON_URL) .then(res => res.json()) .then(json => { // Just focus on the cards which are in the list we want // and do not have a closed status let contentCards = json.cards.filter(card => { return card.idList == TRELLO_LIST_ID && !card.closed; }); return contentCards; }); };

That’ll do it! With this saved in a file called trello.js in Eleventy’s data directory, we’ll have this data ready to use in our templates in an object called trello. 

Done-zo! &#x1f389;

But we can do better. Let’s also handle attached images, and also add a way to have content staged for review before it goes live.

Image attachments

It’s possible to attach files to cards in Trello. When you attach an image, it shows up right there in the card with the source URL of the asset described in the data. We can make use of that!

If a card has an image attachment, we’ll want to get its source URL, and add it as an image tag to what our template inserts into the page at build time. That means adding the Markdown for an image to the Markdown in the description property of our JSON (card.desc). 

Then we can let Eleventy turn that into HTML for us along with everything else. This code looks for cards in our JSON and massages the data into the shape that we’ll need.

// trello.js // If a card has an attachment, add it as an image // in the description markdown contentCards.forEach(card => { if(card.attachments.length) { card.desc = card.desc + `\n![${card.name}](${card.attachments[0].url} '${card.name}')`; } });

Now we can move images around in our content too. Handy!

Staging content

Let’s add one more flourish to how we can use Trello to manage our site’s content.

There are a few ways that we might want to preview content before launching it to the world. Our Trello board could have one list for staging and one list for production content. But that would make it hard to visualize how new content lives alongside that which is already published.

A better idea would be to use Trello’s labels to signify which cards are published live, and which should only be included on a staged version of the site. This will give us a nice workflow. We can add more content by adding a new card in the right place. Label it with “stage” and filter it out from the cards appearing on our production branch. 

Label hints in Trello showing what content is staged and what is live

A little more filtering of our JavaScript object is called for:

// trello.js // only include cards labelled with "live" or with // the name of the branch we are in contentCards = contentCards.filter(card => { return card.labels.filter(label => ( label.name.toLowerCase() == 'live' || label.name.toLowerCase() == BRANCH )).length; });

We want the content labelled ‘live’ to show up on every version of the build, staging or not. In addition we’ll look to include cards which have a label matching a variable called “BRANCH”. 

How come? What’s that?

This is where we get crafty! I’ve chosen to host this site on Netlify (disclaimer: I work there). This means that I can run the build from Netlify’s CI/CD environment. This redeploys the site whenever I push changes to its git repository, and also gives access to a couple of other things which are really handy for this site. 

One is Branch deploys. If you want a new environment for a site, you can create one by making a new branch in the Git repository. The build will run in that context, and your site will be published on a subdomain which includes the branch name. Like this.

Take a look and you’ll see all the cards from our list, including the one which has the orange “stage” label. We included it in this build because its label matched the branch name for the build context. BRANCH was an environment variable which contained whichever branch the build ran in.

label.name.toLowerCase() == BRANCH

In theory, we could make as many branches and labels as we like, and have all sorts of staging and testing environments. Ready to promote something from “stage” to “live”? Swap the labels and you’re good to go!

But how does it update though?

The second perk we get from running the site build in a CI/CD such as Netlify’s is that we can trigger a build to run whenever we like. Netlify lets us create build hooks. These are webhooks which initiate a new deployment when you send an HTTP POST to them.

If Trello supports webhooks too, then we could stitch these services together and refresh the site automatically whenever the Trello board changes. And guess what… they do! Hoorah!

To create a Netlify build hook, you’ll need to visit your site’s admin panel. (You can bootstrap this demo site into a new Netlify site in a couple of clicks if you want to try it out.)

Creating a Netlify Build hook

Now, armed with a new build hook URL, we’ll need to register a new Trello webhook which calls it when content changes. The method for creating webhooks in Trello is via Trello’s API

The repo for this site includes a little utility to call the Trello API and create the webhook for you. But you’ll need to have a Trello developer token and key. Thankfully, it is easy to create those for free by visiting the Trello Developer portal and following the instructions under “Authorizing a client.”

Got ‘em? Great! If you save them in a .env file in your project, you can run this command to set up the Trello webhook:

npm run hook --url https://api.netlify.com/build_hooks/XXXXX

And with that, we’ve created a nice little flow for managing content on a simple site. We can craft our frontend just the way we want it, and have updates to the content happen on a Trello board which automatically updates the site whenever changes are made.

Could I really use this though?

This is a simplistic example. That’s by design. I really wanted to demonstrate the concepts of decoupling, and of using the API of an external service to drive the content for a site.

This won’t replace a full-featured decoupled CMS for more involved projects. But the principles are totally applicable to more complex sites.

This model, however, could be a great match for the types of websites we see for businesses such as independent shops, bars and restaurants. Imagine a Trello board that has one list for managing a restaurant’s home page, and one for managing their menu items. Very approachable for the restaurant staff to manage, and far nicer than uploading a new PDF of the menu whenever it changes.

Ready to explore an example and experiment with your own board and content? Try this:

The post Using Trello as a Super Simple CMS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Bold on Hover… Without the Layout Shift

Css Tricks - Mon, 07/27/2020 - 4:36am

When you change the font-weight of a font, the text will typically cause a bit of a layout shift. That’s because bold text is often larger and takes up more space. Sometimes that doesn’t matter, like a vertical stack of links where the wider/bolder text doesn’t push anything anyway. Sometimes it does matter, like a horizontal row where the wider/bolder text pushes other elements away a smidge.

Ryan Mulligan demonstrates:

Bolding text on mouse hover causes a layout shift that’s especially noticeable when elements start wrapping. Here’s a nifty trick: add a hidden pseudo element with the same text string but set it to the bold font size &#x1f64c;

See it on @CodePen: https://t.co/kBzZXqqtmi pic.twitter.com/kdZBTLQ0RD

— Ryan Mulligan (@hexagoncircle) July 20, 2020

Ryan’s technique is very clever. Each item in the list has a pseudo-element on it with the exact text in the link. That pseudo-element is visually hidden, but pre-bolded and still occupies width. So when the actual link text is bolded, it won’t take up any additional width.

CodePen Embed Fallback

It also sorta depends on how you’re doing the layout. Here, if I force four columns with CSS grid and text that doesn’t really challenge the width, the bolding doesn’t affect the layout either:

CodePen Embed Fallback

But if I were to, say, let those links flow into automatic columns, we would have the shifting problem.

The post Bold on Hover… Without the Layout Shift appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Apple declined to implement 16 Web APIs in Safari due to privacy concerns

Css Tricks - Fri, 07/24/2020 - 12:25pm

Why? Fingerprinting. Rather than these APIs being used for what they are meant for, they end up being used for gross ad tech. As in, “hey, we don’t know exactly who you are, but wait, through a script we can tell your phone stopped being idle from 8:00 am to 8:13 am and were near the Bluetooth device JBL BATHROOM, so it’s probably dad taking his morning poop! Let’s show him some ads for nicer speakers and flannel shirts ASAP.”

I’ll pull the complete list here from Catalin Cimpanu’s article:

  • Web Bluetooth – Allows websites to connect to nearby Bluetooth LE devices.
  • Web MIDI API – Allows websites to enumerate, manipulate and access MIDI devices.
  • Magnetometer API – Allows websites to access data about the local magnetic field around a user, as detected by the device’s primary magnetometer sensor.
  • Web NFC API – Allows websites to communicate with NFC tags through a device’s NFC reader.
  • Device Memory API – Allows websites to receive the approximate amount of device memory in gigabytes.
  • Network Information API – Provides information about the connection a device is using to communicate with the network and provides a means for scripts to be notified if the connection type changes
  • Battery Status API – Allows websites to receive information about the battery status of the hosting device.
  • Web Bluetooth Scanning – Allows websites to scan for nearby Bluetooth LE devices.
  • Ambient Light Sensor – Lets websites get the current light level or illuminance of the ambient light around the hosting device via the device’s native sensors.
  • HDCP Policy Check extension for EME – Allows websites to check for HDCP policies, used in media streaming/playback.
  • Proximity Sensor – Allows websites to retrieve data about the distance between a device and an object, as measured by a proximity sensor.
  • WebHID – Allows websites to retrieve information about locally connected Human Interface Device (HID) devices.
  • Serial API – Allows websites to write and read data from serial interfaces, used by devices such as microcontrollers, 3D printers, and othes.
  • Web USB – Lets websites communicate with devices via USB (Universal Serial Bus).
  • Geolocation Sensor (background geolocation) – A more modern version of the older Geolocation API that lets websites access geolocation data.
  • User Idle Detection – Lets website know when a user is idle.

I’m of mixing feelings. I do like the idea of the web being a competitive platform for building any sort of app and sometimes fancy APIs like this open those doors.

Not to mention that some of these APIs are designed to do responsible things, like knowing connections speeds through the Network Information API and sending less data if you can, and the same for the Battery Status API.

This is all a similar situation to :visited in CSS. Have you ever noticed how there are some CSS declarations you can’t use on visited links? JavaScript APIs will even literally lie about the current styling of visited links to make links always appear unvisited. Because fingerprinting.

Direct Link to ArticlePermalink

The post Apple declined to implement 16 Web APIs in Safari due to privacy concerns appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

A Font-Like SVG Icon System for Vue

Css Tricks - Fri, 07/24/2020 - 4:07am

Managing a custom collection of icons in a Vue app can be challenging at times. An icon font is easy to use, but for customization, you have to rely on third-party font generators, and merge conflicts can be painful to resolve since fonts are binary files.

Using SVG files instead can eliminate those pain points, but how can we ensure they’re just as easy to use while also making it easy to add or remove icons?

Here is what my ideal icon system looks like:

  • To add icons, you just drop them into a designated icons folder. If you no longer need an icon, you simply delete it.
  • To use the rocket.svg icon in a template, the syntax is as simple as <svg-icon icon="rocket" />.
  • The icons can be scaled and colored using the CSS font-size and color properties (just like an icon font).
  • If multiple instances of the same icon appear on the page, the SVG code is not duplicated each time.
  • No webpack config editing is required.

This is what we will build by writing two small, single-file components. There are a few specific requirements for this implementation, though I’m sure many of you wizards out there could rework this system for other frameworks and build tools:

  • webpack: If you used the Vue CLI to scaffold your app, then you’re already using webpack.
  • svg-inline-loader: This allows us to load all of our SVG code and clean up portions we do not want. Go ahead and run npm install svg-inline-loader --save-dev from the terminal to get started.
The SVG sprite component

To meet our requirement of not repeating SVG code for each instance of an icon on the page, we need to build an SVG “sprite.” If you haven’t heard of an SVG sprite before, think of it as a hidden SVG that houses other SVGs. Anywhere we need to display an icon, we can copy it out of the sprite by referencing the id of the icon inside a <use> tag like this:

<svg><use xlink:href="#rocket" /></svg>

That little bit of code is essentially how our <SvgIcon> component will work, but let’s go ahead create the <SvgSprite> component first. Here is the entire SvgSprite.vue file; some of it may seem daunting at first, but I will break it all down.

<!-- SvgSprite.vue --> <template>   <svg width="0" height="0" style="display: none;" v-html="$options.svgSprite" /> </template> <script> const svgContext = require.context(   '!svg-inline-loader?' +    'removeTags=true' + // remove title tags, etc.   '&removeSVGTagAttrs=true' + // enable removing attributes   '&removingTagAttrs=fill' + // remove fill attributes   '!@/assets/icons', // search this directory   true, // search subdirectories   /\w+\.svg$/i // only include SVG files ) const symbols = svgContext.keys().map(path => {   // get SVG file content   const content = svgContext(path)    // extract icon id from filename   const id = path.replace(/^\.\/(.*)\.\w+$/, '$1')   // replace svg tags with symbol tags and id attribute   return content.replace('<svg', `<symbol id="${id}"`).replace('svg>', 'symbol>') }) export default {   name: 'SvgSprite',   svgSprite: symbols.join('\n'), // concatenate all symbols into $options.svgSprite } </script>

In the template, our lone <svg> element has its content bound to $options.svgSprite. In case you’re unfamiliar with $options it contains properties that are directly attached to our Vue component. We could have attached svgSprite to our component’s data, but we don’t really need Vue to set up reactivity for this since our SVG loader is only going to run when our app builds.

In our script, we use require.context to retrieve all of our SVG files and clean them up while we’re at it. We invoke svg-inline-loader and pass it several parameters using syntax that is very similar to query string parameters. I’ve broken these up into multiple lines to make them easier to understand.

const svgContext = require.context( '!svg-inline-loader?' + 'removeTags=true' + // remove title tags, etc. '&removeSVGTagAttrs=true' + // enable removing attributes '&removingTagAttrs=fill' + // remove fill attributes '!@/assets/icons', // search this directory true, // search subdirectories /\w+\.svg$/i // only include SVG files )

What we’re basically doing here is cleaning up the SVG files that live in a specific directory (/assets/icons) so that they’re in good shape to use anywhere we need them.

The removeTags parameter strips out tags that we do not need for our icons, such as title and style. We especially want to remove title tags since those can cause unwanted tooltips. If you would like to preserve any hard-coded styling in your icons, then add removingTags=title as an additional parameter so that only title tags are removed.

We also tell our loader to remove fill attributes, so that we can set our own fill colors with CSS later. It’s possible you will want to retain your fill colors. If that’s the case, then simply remove the removeSVGTagAttrs and removingTagAttrs parameters.

The last loader parameter is the path to our SVG icon folder. We then provide require.context with two more parameters so that it searches subdirectories and only loads SVG files.

In order to nest all of our SVG elements inside our SVG sprite, we have to convert them from <svg> elements into SVG <symbol> elements. This is as simple as changing the tag and giving each one a unique id, which we extract from the filename.

const symbols = svgContext.keys().map(path => { // extract icon id from filename const id = path.replace(/^\.\/(.*)\.\w+$/, '$1') // get SVG file content const content = svgContext(path) // replace svg tags with symbol tags and id attribute return content.replace('<svg', `<symbol id="${id}"`).replace('svg>', 'symbol>') })

What do we do with this <SvgSprite> component? We place it on our page before any icons that depend on it. I recommend adding it to the top of the App.vue file.

<!-- App.vue --> <template>   <div id="app">     <svg-sprite /> <!-- ... --> The icon component

Now let’s build the SvgIcon.vue component.

<!-- SvgIcon.vue --> <template>   <svg class="icon" :class="{ 'icon-spin': spin }">     <use :xlink:href="`#${icon}`" />   </svg> </template> <script> export default {   name: 'SvgIcon',   props: {     icon: {       type: String,       required: true,     },     spin: {       type: Boolean,       default: false,     },   }, } </script> <style> svg.icon {   fill: currentColor;   height: 1em;   margin-bottom: 0.125em;   vertical-align: middle;   width: 1em; } svg.icon-spin {   animation: icon-spin 2s infinite linear; } @keyframes icon-spin {   from {     transform: rotate(0deg);   }   to {     transform: rotate(359deg);   } } </style>

This component is much simpler. As previously mentioned, we leverage the <use> tag to reference an id inside our sprite. That id comes from our component’s icon prop.

I’ve added a spin prop in there that toggles an .icon-spin class as an optional bit of animation, should we ever need. This could, for example, be useful for a loading spinner icon.

<svg-icon v-if="isLoading" icon="spinner" spin />

Depending on your needs, you may want to add additional props, such as rotate or flip. You could simply add the classes directly to the component without using props if you’d like.

Most of our component’s content is CSS. Other than the spinning animation, most of this is used to make our SVG icon act more like an icon font¹. To align the icons to the text baseline, I’ve found that applying vertical-align: middle, along with a bottom margin of 0.125em, works for most cases. We also set the fill attribute value to currentColor, which allows us to color the icon just like text.

<p style="font-size: 2em; color: red;">   <svg-icon icon="exclamation-circle" /><!-- This icon will be 2em and red. -->   Error! </p>

That’s it!  If you want to use the icon component anywhere in your app without having to import it into every component that needs it, be sure to register the component in your main.js file:

// main.js import Vue from 'vue' import SvgIcon from '@/components/SvgIcon.vue' Vue.component('svg-icon', SvgIcon) // ... Final thoughts

Here are a few ideas for improvements, which I intentionally left out to keep this solution approachable:

  • Scale icons that have non-square dimensions to maintain their proportions
  • Inject the SVG sprite into the page without needing an additional component.
  • Make it work with vite, which is a new, fast (and webpack-free) build tool from Vue creator Evan You.
  • Leverage the Vue 3 Composition API.

If you want to quickly take these components for a spin, I’ve created a demo app based on the default vue-cli template. I hope this helps you develop an implementation that fits your app’s needs!

¹ If you’re wondering why we’re using SVG when we want it to behave like an icon font, then check out the classic post that pits the two against one another.

The post A Font-Like SVG Icon System for Vue appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Holy Albatross with Widths

Css Tricks - Fri, 07/24/2020 - 4:07am

Heydon’s Holy Albatross is a technique to have a row of elements break into a column of elements at a specific width. A specified parent width, not a screen width like a media query would have. So, like a container query (ya know, those things that don’t exist yet that we all want).

I’ve used it before, although it was pointed out to me that using it only on two elements isn’t really necessary, and that the Holy Albatross is most useful when working with three or more elements.

The original article kind didn’t get into setting the widths on the horizontal row of elements (say one of them needs to be larger than the others), but the follow-up article has a demo in it showing that flex-grow can be used to do exactly that. But Xiao Zhuo Jia notes that it’s not exactly a great system:

Problem is, it’s very difficult to set width to your non-stacked column, because the width is taken over by the hack.

One suggestion by Heydon is to use flex-grow, the problems are:

1. It is a very unintuitive way to set width – for a 3 column layout, you want 1 column to be 50% wide, you have to set flex-grow to 2.333
2. You have to know the number of total columns and set other columns’ flex-grow value accordingly

The other method is to use min-width and max-width, as shown by this codepen. I don’t believe max-width: 100% is needed as anything larger than 100% will be changed to 100% due to flex-shrink, so really we’re dealing with min-width.

The problem with this method is that we have to set min-width for all columns, or else flex-grow will take over and expand the column beyond the min-width we’ve set.

None of this is fun.

I poked around a bit and I found that you can have your cake and eat it too…

Xiao Zhuo Jia calls the Unholy Albatross. Check out the How does it work? part of the article to see the great CSS trickery. It has to do with using the max() function and CSS custom properties with fullbacks. It still feels very in the spirit of the Holy Albatross and allows you to set the width (via --width) on any given element with a pixel value or ratio. Plus, it supports gaps.

CodePen Embed Fallback

Direct Link to ArticlePermalink

The post Holy Albatross with Widths appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

WordPress.com Growth Summit

Css Tricks - Thu, 07/23/2020 - 11:48am

I’m speaking at The Official WordPress.com Growth Summit coming up in August. “Learn how to build and grow your site, from start to scale”, as they say. Lovely, thick, diverse set of speakers. It’s a little bit outside my normal spheres which makes it extra exciting for me. Selena Jackson:

The goal of this event is to inspire, connect you with the tools you need, and help you build your community. Sessions will take place across three tracks: blogging, business, and creative. You can take sessions on any or all tracks

If it interests you, it’s $79, and 20% off that with coupon code ChrisCoyier20.

My session?

CSS-Tricks: Putting WordPress to Work

Chris Coyier’s CSS-Tricks is a popular publication geared to web designers and developers. It’s also very much a business powered by WordPress. Chris will take us behind the scenes at CSS-Tricks, sharing all the ways it takes advantage of WordPress features, on both the technical and business sides.

Selena sent me some interesting questions as well:

What has kept you on WordPress for all these years? How has your website been essential to your growth or success?

It’s true that CSS-Tricks has never been anything but a WordPress site. I’ve never switched platforms or majorly re-architected in any way. But it’s not because of laziness or because I just don’t have any exposure to other methods of website building. I feel fortunate in that I’ve had lots of exposure and experience to different ways to build websites, from JAMstack with static site generators with cloud functions, to CMSs of all sorts, to Ruby on Rails sites, to Python-based sites… all kinds of stuff. All of it has a place.

Part of the equation is that I’m a solo developer for the most part on CSS-Tricks. Just me over here. I don’t have the budget for a fancy development team. But I still want to feel powerful and productive. That’s one of the things that WordPress has given to me. I feel like I can build just about anything on WordPress, and do it in a way that doesn’t feel like a mountain of technical debt that I would struggle to maintain.

Even though there is a decent amount of custom stuff going on, it probably looks like more than it is. Most of the work I do is pretty normcore WordPress development. I use popular well-maintained plugins. I use standard filters. I use the templating system as it was designed. I try to do things “The WordPress Way”, and that means year after year it’s very easy for me to maintain the site and build out what I want to build out. I never worry if I’m going against the grain or that I’m doing anything that puts me at any risk of not being able to upgrade things.

What’s one key thing you want our Growth Summit attendees to take away from your keynote talk/session?

I think my main vibe is going to be sharing just how powerful WordPress can be as a platform to run a publishing business on.

In a crowded and noisy web environment, what did you do to help your website stand out? What’s unique about your story or business?

What I hope we stand out for is the content on the site itself. We strive to be consistent, trustworthy, friendly, and helpful. In a world so laden with misinformation, zero-ethics advertising, and UX-hostile interfaces trying to squeeze everything they can from you, a site that’s just trying to help you understand the web and run a normal business out of it I hope feels as good to other people as it does to me.

Has COVID-19 changed how you use your website — or your approach to your online presence?

Not terribly. I’m finding advertisers pulling back a little bit, and keeping a closer eye on their sponsorship investments. And while I don’t love the idea of seeing those dollars go down, I don’t blame them. It’s smart for any business to make sure their money is well-spent.

The post WordPress.com Growth Summit appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Accordion Rows in CSS Grid

Css Tricks - Thu, 07/23/2020 - 10:15am

I’d bet grid-template-columns is used about 10× more than grid-template-rows, but maybe everyone has just been missing out. Eric Meyer chucks a bunch of row lines onto his main site layout grid like this:

grid-template-rows: repeat(7, min-content) 1fr repeat(3, min-content);

That way, if you need to use them they are they for you:

like this pattern. It feels good to me, having two sets of rows where the individual rows accordion open to accept content when needed, and collapse to zero height when not, with a “blank” row in between the sets that pushes them apart. It’s flexible, and even allows me to add more rows to the sets without having to rewrite all my layout styles.

Direct Link to ArticlePermalink

The post Accordion Rows in CSS Grid appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Vue 3.0 has entered Release Candidate stage!

Css Tricks - Thu, 07/23/2020 - 4:57am

Vue is in the process of a complete overhaul that rebuilds the popular JavaScript framework from the ground up. This has been going on the last couple of years and, at long last, the API and implementation of Vue 3 core are now stabilize. This is exciting for a number of reasons:

  • Vue 3 promises to be much more performant than Vue 2.
  • Despite being a complete rewrite, the surface API hasn’t changed drastically, so there’s no need to forget what you already know about Vue.
  • The Vue documentation was completely migrated revised. (If you see me celebrating that, it’s because I helped work on it.)
  • There are several new features — like the Composition API (inspired by React Hooks) — that are additive and helpful for composition between multiple components.

Here’s how you can get your hands on the Vue 3 release candidate:

There is more information about DevTools, experimental features and more in the release notes.

Docs updates, now in beta

Why am I so excited about the Vue doc updates? Because the updates include but are not limited to:

We are still actively working on things, of course, so if you see to-dos or unresolved work, please let us know! Feel free to open an issue or PR over at GitHub but, please, note that large requests will likely be closed out while we’re still refining our current work.

All in all we think you’ll enjoy it! It’s all the features you know and love, with some extra lovely bits, plus excellent performance.

The post Vue 3.0 has entered Release Candidate stage! appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CMD+Z for Git is Here

Css Tricks - Thu, 07/23/2020 - 4:57am

Version control with Git has become a “commodity” by now: virtually every software project today uses Git, and virtually every developer knows Git to some extent. This explains why I sometimes hear the following question when I talk about what I do for a living: “A desktop client for Git? Why would I need that? I can do that on the command line!

If I’m lucky, I have a computer next to me when that question hits me. And instead of producing a wordy answer, I do a couple of things in Tower, our desktop client for Git.

Anyone who’s ever performed an “Interactive Rebase” is amazed by how easy that is in Tower: you simply drag and drop to combine commits or reorder them. And anyone who hasn’t yet used “Interactive Rebase” – because it was too complicated and clunky to use on the command line – now understands that it’s a very valuable tool.

Or I might make a mistake: accidentally deleting a branch or messing up a merge in a terrible way. And I’ll simply hit CMD+Z, like I would in a text editor, to undo the mess I just made.

People then start to realize that the real question is not: “Can I get by using Git on the command line?” The more important questions are:

  • Can I use all of Git’s power? (Even the advanced features that might be hard to use, but that can be very valuable…)
  • Can I work with Git in a productive way? (Not having to look up parameters, not spending too much time on my workflows…)
  • Can I work with Git in an easy way? (Without having to think about it too much…)

We – a small team of just 9 people – have spent the last 10 years answering those questions by building Tower.

How to Undo Mistakes

One of Git’s greatest features is that it allows you to undo almost anything. However, it requires quite some experience to know how exactly to undo your particular kind of mess: a failed merge has to be cleaned up differently than a deleted branch!

After working on this for a long time, Tower now allows you to undo virtually anything – simply by pressing CMD+Z! (Note: the “Undo” feature is a quite recent addition and first available in the Mac version of Tower. It will soon come to Windows, too).

No matter if you messed up a merge, inadvertently deleted a branch, discarded a valuable local change, published a branch on a remote too soon, or simply committed something that you shouldn’t have – your lifesaver is as simple as “CMD+Z”, and it’s always available.

The Power of Interactive Rebase

Interactive Rebase is a wonderful example of Git’s more powerful features. It allows you to…

  • edit old commits (both their messages as well as their changesets!)
  • combine multiple commits into one
  • reorder commits
  • …and even delete commits you don’t need anymore!

All of these can help a lot to keep a code base clean and structured. But being a very powerful tool, Interactive Rebase is also an example of a Git feature that is quite complicated to use!

Many beginners are scared away by this complexity – meaning that, of course, they will miss out on the benefits of the feature! Many experienced developers know and use Interactive Rebase; but since the feature is hard to use, it costs them a lot of time and/or they make mistakes from time to time.

Knowing this, we had two goals for integrating Interactive Rebase into Tower: on the one hand, we wanted to reduce as much of its complexity as possible. And on the other hand, we wanted to make the feature easily accessible.

The result is that Interactive Rebase is now integrated right into the “Commit History” and accessible via simple drag & drop and menu options:

Countless developers that wouldn’t have used Interactive Rebase at all on the Command Line are now using it on a daily basis in Tower.

Quick Actions

Almost independent of its size, working in a code base means spending a lot of time searching: for example for a certain branch (out of lots of branches) or a certain file (out of lots of files).

Tower allows you to do most of your daily tasks without sifting through data – and even without taking your hands off the keyboard. The “Quick Action” dialog takes almost any input and allows you to simply act on it:

  • Give it a branch name and it will offer to do a checkout.
  • Give it a file name and it will offer to show it in the File History.
  • Give it a commit hash and it will offer to show that commit’s details.

Being able to perform many tasks right from the keyboard, without having to search and sift through loads of data, can make life as a developer a lot easier.

Solving Conflicts with Confidence

Everyone hates that moment when a merge (or rebase) stops and leaves you with a bunch of conflicts &#x1f631; Multiple questions then quickly enter the poor programmer’s mind:

  • What are my changes? What are someone else’s?
  • What actually happened?
  • Why me?

While, admittedly, Tower cannot answer all of those questions, it offers a special “Conflict Wizard” that helps make the situation much more understandable:

You can easily see where changes came from and can solve the conflict simply by choosing which version to go with (or jump into a dedicated merge tool). It makes things a lot easier when merge conflicts are visualized in this way, instead of being an abstract mess.

Becoming More Productive

When building and improving Tower, we’re always striving to make things easier for our users – and to make them more productive. Let’s take some examples of where this shows in Tower:

  • No More Passwords, Tokens, SSH Keys: You can easily connect your GitHub / GitLab / Bitbucket / Azure DevOps accounts with Tower. Once connected, you never have to wrestle with passwords, authentication, tokens, usernames, and SSH Keys anymore. Cloning and interacting with a remote repository, then, is a matter of just a click.
  • Single-Line Staging & Discarding: There’s a golden rule in version control: when you make a commit, you should only include changes from a single topic (and not mix multiple topics in a commit, thereby making it extremely hard to understand what actually happened). With the ability to stage / unstage / discard individual chunks and lines from your changes, Tower enables you to create granular, precise commits.
  • A New Diff Viewer: In a very recent update, we gave our internal Diff Viewer a complete overhaul. It now highlights inline changes, allows you to show/hide whitespace changes, can display the complete file, and is completely customizable with themes!
  • Automations for the Boring Stuff: Tower takes care of much of the grunt work around Git. To take just two examples: neither do you have to regularly fetch new updates from the remote, nor do you have to remember to stage uncommitted changes before pulling/switching branches/merging… Tower does that automatically for you.

When I think about the favorite applications I use myself, they all have some things in common: they make life easier for me, they make me more productive, and they enable me to do advanced stuff that I’d have a hard time doing without them. I’m glad and grateful that many of our users consider Tower to be one of their favorite apps!

If you want to give Tower a try, just download it from our website and test it 30 days for free. And if you are a student or teacher, you can use Tower for free!

The post CMD+Z for Git is Here appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Position Vertical Scrollbars on Opposite Side with CSS

Css Tricks - Wed, 07/22/2020 - 1:29pm

Fair warning: I can’t say I recommend this in general because it breaks a very strong expectation of where scrollbars are, which are useful for a lots of folks, not to mention, a core accessibility feature for many.

But it is a fascinating CSS trick and the web is a big place with an unknowable magnitude of situations where sometimes weird solutions are needed.

Technique #1: Directional Trickery

The trick here is to have the scrolling parent element use direction: rtl (or the opposite of whatever your primary direction is), and have the inside of the scrolling element switch back to whatever your normal is.

CodePen Embed Fallback Technique #2: Rotational Trickery

Messing with text direction for non text-direction purposes always feels a little scary to me, so this trick feels less hacky. The trick is to rotate the parent 180deg, and then the child back another 180deg so it’s upright again.

Because of the first rotation, the scrollbar ends up on the opposite side.

CodePen Embed Fallback

This one is especially awkward for two reasons:

  1. The scrolling element is scrolled to the bottom by default
  2. The scroll direction feels reversed with a scroll wheel. The scrollbar itself should behave somewhat as expected, but a trackpad or mouse scrollwheel will feel like the scroll direction has been reversed in that element.

More like an April Fool’s joke than something you’d really use. A viral tweet called it cursed, which, yes.

The post Position Vertical Scrollbars on Opposite Side with CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

WordPress-Powered Landing Pages on a Totally Different Site via Cloudflare Workers

Css Tricks - Wed, 07/22/2020 - 9:39am

What if you have some content on one site and want to display that content on another site? We can do this in the browser no problem. We can fetch it, and plunk it onto the page.

Ajax, right? Ugh. Now we’re in client-side rendered site territory, which isn’t great for performance, speed, or resiliency.

What if we could fetch that content and stitch it into the main page on the server side? Server side isn’t the right word for it though. What if we could do it at the global CDN level? Do it at the edge, as they say. That’s what we’ve been doing at CodePen, so we can build pages with the lovely WordPress block editor but serve them on our main site.

Direct Link to ArticlePermalink

The post WordPress-Powered Landing Pages on a Totally Different Site via Cloudflare Workers appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Pausing a GIF with details/summary

Css Tricks - Wed, 07/22/2020 - 5:15am

Steve Faulkner has a clever idea here. You can show an (animated) GIF and overlay a pause/play button on top of it — which is really a <details>/<summary> element. When toggled, a (non-animated) JPG inside covers the GIF, effectively “pausing” it.

Adrian Roselli calls it a “quick and dirty” way to pass WCAG Success Criterion 2.2.2 Pause, Stop, Hide.

I forked it, swapped out all the images so it shows the JPG first, and put loading="lazy" on the images. It seems to effectively not load the GIF until you explicitly press play, so that’s an option too:

CodePen Embed Fallback

The post Pausing a GIF with details/summary appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Reactive jQuery for Spaghetti-fied Legacy Codebases (or When You Can’t Have Nice Things)

Css Tricks - Wed, 07/22/2020 - 4:50am

I can hear you crying out now: “Why on Earth would you want to use jQuery when there are much better tools available? Madness! What sort of maniac are you?” These are reasonable questions, and I’ll answer them with a little bit of context.

In my current job, I am responsible for the care and feeding of a legacy website. It’s old. The front-end relies on jQuery, and like most old legacy systems, it’s not in the best shape. That alone isn’t the worst, but I’m working with additional constraints. For example, we’re working on a full rewrite of the system, so massive refactoring work isn’t being approved, and I’m also not permitted to add new dependencies to the existing system without a full security review, which historically can take up to a year. Effectively, jQuery is the only JavaScript library I can use, since it’s already there. 

My company has only recently come to realize that front-end developers might have important skills to contribute, so the entire front end of the app was written by developers unaware of best practices, and often contemptuous of their assignment. As a result, the code quality is wildly uneven and quite poor and unidiomatic overall.

Yeah, I work in that legacy codebase: quintessential jQuery spaghetti.

Someone has to do it, and since there will always be more legacy code in the world than greenfield projects, there will always be lots of us. I don’t want your sympathy, either. Dealing with this stuff, learning to cope with front-end spaghetti on such a massive scale has made me a better, if crankier, developer.

So how do you know if you’ve got spaghetti jQuery on your hands? One reliable code smell I’ve found is a lack of the venerable old .toggle(). If you’ve managed to successfully not think about jQuery for a while, it is a library that smooths cross-browser compatibility issues while also making DOM queries and mutations incredibly easy. There’s nothing inherently wrong with that, but direct DOM manipulation can be very hard to scale if you’re not careful. The more DOM-manipulation you write, the more defensive against DOM mutation you become. Eventually, you can find yourself with an entire codebase written that way and, combined with less-than-ideal scope management, you are essentially working in an app where all of the state is in the DOM and you can never trust what state the DOM will be in when you need to make changes; changes could swoop in from anywhere in your app whether you like it or not. Your code gets more procedural, bloating things up with more explicit instructions, trying to pull all the data you need from the DOM itself and force it into the state you need it to be in.

This is why .toggle() is often the first thing to go: if you can’t be sure whether an element is visible or not, you have to use .show() and .hide() instead. I’m not saying .show() and .hide() should be Considered Harmful™, but I’ve found they’re a good indication that there might be bigger problems afoot.

What can you do to combat this? One solution my coworkers and I have found takes a hint directly from the reactive frameworks we’d rather be using: observables and state management. We’ve all found that hand-rolling state objects and event-driven update functions while treating our DOM like a one-way dataflow template leads to more predictable results that are easier to change over time.

We each approach the problem a little differently. My take on reactive jQuery is distinctly flavored like Vue drop-in and takes advantage of some “advanced” CSS.

CodePen Embed Fallback

If you check out the script, you’ll see there are two different things happening. First, we have a State object that holds all of the values for our page, and we have a big mess of events.

var State = { num: 0, firstName: "", lastName: "", titleColor: "black", updateState: function(key, value){ this[key] = value; $("[data-text]").each(function(index, elem){ var tag = $(elem).attr("data-tag"); $(elem).text(State[tag]); }); $("[data-color]").each(function(index, elem){ var tag = $(elem).attr("data-tag"); $(elem).attr("data-color", State[tag]); }); } };

I’ll admit it, I love custom HTML attributes, and I’ve applied them liberally throughout my solution. I’ve never liked how HTML classes often do double-duty as CSS hooks and JavaScript hooks, and how if you use a class for both purposes at once, you’ve introduced brittleness into your script. This problem goes away completely with HTML attributes. Classes become classes again, and the attributes become whatever metadata or styling hook I need.

If you look at the HTML, you’ll find that every element in the DOM that needs to display data has a data-tag attribute with a value that corresponds to a property in the State object that contains the data to be displayed, and an attribute with no value that describes the sort of transformation that needs to happen to the element it’s applied to. This example has two different sorts of transformations, text and color.

<h1 data-tag="titleColor" data-color>jDux is super cool!</h1>

On to the events. Every change we want to make to our data is fired by an event. In the script, you’ll find every event we’re concerned about listed with its own .on() method. Every event triggers an update method and sends two pieces of information: which property in the State object that needs to be updated, and the new value it should be set to.

$("#inc").on("click", function(){ State.updateState("num", State.num + 1) }); $("#dec").on("click", function(){ State.updateState("num", State.num - 1) }); $("#firstNameInput").on("input", function(){ State.updateState("firstName", $(this).val() ) }); $("#lastNameInput").on("input", function(){ State.updateState("lastName", $(this).val() ) }); $('[class^=button]').on("click", function(e) { State.updateState('titleColor', e.target.innerText); });

This brings us to State.updateState(), the update function that keeps your page in sync with your state object. Every time it runs, it updates all the tagged values on the page. It’s not the most efficient thing to redo everything on the page every time, but it’s a lot simpler, and as I hope I’ve already made clear, this is an imperfect solution for an imperfect codebase.

$(document).ready(function(){ State.updateState(); });

The first thing the update function does is update the value according to the property it receives. Then it runs the two transformations I mentioned. For text elements, it makes a list of all data-text nodes, grabs their data-tag value, and sets the text to whatever is in the tagged property. Color works a little differently, setting the data-color attribute to the value of the tagged property, and then relies on the CSS, which styles the data-color properties to show the correct style.

I’ve also added a document.ready, so we can run the update function on load and display our default values. You can pull default values from the DOM, or an AJAX call, or just load the State object with them already entered as I’ve done here.

And that’s it! All we do is keep the state in the JavaScript, observe our events, and react to changes as they happen. Simple, right?

What’s the benefit here? Working with a pattern like this maintains a single source of truth in your state object that you control, you can trust and you can enforce. If you ever lose trust that your DOM is correct, all you need to do is re-run the update function with no arguments and your values become consistent with the state object again.

Is this kind of hokey and primitive? Absolutely. Would you want to build an entire system out of this? Certainly not. If you have better tools available to you, you should use them. But if you’re in a highly restrictive legacy codebase like I am, try writing your next feature with Reactive jQuery and see if it makes your code, and your life, simpler.

The post Reactive jQuery for Spaghetti-fied Legacy Codebases (or When You Can’t Have Nice Things) appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

What ya need there is a bit of templating

Css Tricks - Tue, 07/21/2020 - 2:23pm

I had a fella write in to me the other day. He had some HTML, CSS, and JavaScript, and it just wasn’t behaving like he thought it ought to. The HTML had some placeholders in it and the JavaScript had some data in it, and the assumption was that the data would fill the placeholders.

To those of us with some degree of web knowledge, we can look at this and see why it’s not working like he thought it would. But I think it’s also valuable to try to see things from that perspective and then look at solutions that are hopefully as simple as the original problem seems to be.

The HTML was something like this… <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Test</title> <link rel="stylesheet" href="test.css"> <script src="data.js"></script> </head> <body> <section> <div>{company_name}</div> </section> </body> </html> The JavaScript was like this… var company_data = { "{company_name}" : "SOME COMPANY", }; There is nothing invalid going on here.

That’s all perfectly valid code. It is linked up right. It will run. It just doesn’t do anything besides render {company_name} to the screen. The expectation is that it would render SOME COMPANY to the screen instead, replacing the {company_name} placeholder with the data from the JavaScript file.

Let’s fix it with a one-liner.

In this exact scenario, to display the correct company name, we need to select that element in the DOM and replace its content with our data. We could do that by adding this one extra line to the JavaScript:

var company_data = { "{company_name}": "SOME COMPANY" }; document.querySelector("div").innerHTML = company_data["{company_name}"];

That’s not particularly re-usable or resiliant, but hey, it’s also not over-thinking or over-tooling it.

The expectation was templating

I think we can see at this point that what he hoped would happen is that this sort of templating would automatically happen. Provide an object with keys that match what is in the HTML, the content in that HTML is automatically swapped out. It just doesn’t work that way with raw web technologies.

No joke, there are hundreds of ways to go about handling this. Here’s a few off the top of my head:

  • Use a templating language like Handlebars or Mustache
  • Use a static site generator like Eleventy, which uses Liquid by default
  • Make an HTML <template> and write your own script to use it
  • Make a Web Component
  • Use a back-end language instead, or a language like Nunjucks to process ahead of time
  • Use a preprocessor like Pug

As a general preference, I’d say doing the templating server-side or during a build is ideal — why mess with the DOM if you don’t need to?

But just to ignore that advice for a second, here’s an example of doing it client-side with Handlebars, just so the fella from the original email has a working example of how that can work:

CodePen Embed Fallback

The post What ya need there is a bit of templating appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Using Flexbox and text ellipsis together

Css Tricks - Tue, 07/21/2020 - 12:19pm

You can truncate a single line of text with an ellipsis (…) fairly easily with text-overflow and a few friends. But, as you might expect, that truncation happens at the end of the line of text. What if you want to truncate content in the middle?

Leonardo Faria details good use cases for this, like in an operating system window listing files. The line of text is a file name and a file extension. When that line truncates, it truncates just the name, always leaving the extension at the end. The trick is a flexbox parent so you can use overflow on just the file name part, but have to make sure to reset the min-width, as the natural value there is min-content, which prevents the truncation which is confusing.

CodePen Embed Fallback

Direct Link to ArticlePermalink

The post Using Flexbox and text ellipsis together appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

marketstack: A Market Data API

Css Tricks - Tue, 07/21/2020 - 4:46am

(This is a sponsored post.)

I like the apilayer company tagline: “Automate What Should Be Automated.” They have this thick suite of products that are all APIs with clear documentation. They all have usable free tiers to develop against and prove out an idea, and then paid plans if you need to start using the APIs more aggressively. They have a brand new one: marketstack.

With this API, you have access to stock market data both current and historical. Got an idea for an app (or business!) that needs stock data? Wanna chart out how Apple is doing? Hit the REST API with your key and the AAPL stock symbol and you’ll get back just the JSON data you need. If you’ve always wanted to build a stock market app, this totally opens that door.

That’s what I love about stuff like this. I’ve seen so many people with startup ideas, but then end up being limited by the fact that they just don’t have the data they need to make it actually useful. So many business ideas are really founded on what kind of data you have access to. APIs like marketstack open those doors in affordable ways to everyone.

I think picking out technology stacks is fun, even just to think about. Like doesn’t it sound fun to build an Electron app with something like Electron Forge so you have a React+webpack setup, then hit the marketstack API for interesting market data and use nivo to build charts, chucking whatever data you need to save into Fauna?

Direct Link to ArticlePermalink

The post marketstack: A Market Data API appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

When do you use inline-block?

Css Tricks - Mon, 07/20/2020 - 11:08am

The inline-block value for display is a classic! It’s not new and browser support is certainly not something you need to worry about. I’m sure many of us reach for it intuitively. But let’s put a point on it. What is it actually useful for? When do you pick it over other, perhaps similar, options?

(I bet this makes for interesting replies.)

What is the last thing you used `display: inline-block` for?

— Chris Coyier (@chriscoyier) June 19, 2020 Buttons

The most common answer I heard was: I always use it on buttons.

Ultimately, I think that makes sense, but it contributes to a what I see as a slight misunderstanding. The idea is that you want elements that look like buttons (which might be crafted with <a>, <button>, or perhaps <input>) to lay inline — like they do naturally — but be able to have margin and padding. That’s the slight misunderstanding part: display: inline; elements can still have margin and padding, and it probably behaves like you expect it to.

The tricky part is that:

  • The block-direction margin on inline elements is ignored entirely
  • The padding on inline elements doesn’t affect the height of the line of text

So, while the buttons themselves are pretty much styled just fine, the parent element and surrounding text probably isn’t. Here’s a demo that:

The padding from the inline buttons breaks them out of the container, which is a little weird.

Things get worse when wrapping starts to happen with inline buttons:

So yeah, inline-block makes pretty good sense on buttons I’d say. But…

Don’t forget inline-flex and inline-grid

With the display values inline-flex and inline-grid, you’ll get all the same good behavior that you will from inline-block, but the elements (often buttons) can benefit from a stronger inline layout system.

Take the example of buttons-with-icons, like this:

<a href="#" class="button> <svg> ... </svg> Text </a>

To get the text and icon aligned perfectly in the center, it’s tempting to do like:

.button svg { vertical-align: middle; }

Which never gets it quite right…

Those icons are sitting a pixel or two too low from center, at least to my eye.

But this is an easy fix with inline-flex:

.button { display: inline-flex; align-items: center; } Perfectly aligned icons (and someday we’ll be able to size using lh units nicely!)

With inline-flex or inline-grid, you have all the power of a flexbox or grid layout system within a block that lays out in the inline direction.

Blocks that can still wrap

An inline-block elements will respect a width. That’s another difference between them and straight-up inline elements. People used to¹ build column layout systems with inline-block, because it basically can do what floats could do here, except without the need to worry about clearing the float², allowing people to take advantage of wrapping which happens a bit more elegantly than float.

The idea of inline-blocks behaving like columns that can wrap (even down to 1 column) lives on to this day because it’s a trick that can be used in HTML emails to allow for multi-column layouts that collapse to single-column on small screens without the need for media queries (which some email clients don’t support).

Yesterday in an HTML email, on divs that wrap tables, to allow for responsive columns without media queries

— Dan Denney (@dandenney) June 19, 2020

Dan’s example.

transform on an inline element

Inline elements can’t take a transform. So if you need that, it’ll need to be inline-block.

CodePen Embed Fallback Column children that don’t break in the middle of themselves

CSS columns can be used on paragraphs of text where you don’t really care if any given paragraph breaks across columns. But sometimes CSS columns are used for blocks where that would be awkward. Say the blocks have their own backgrounds and padding. The breaks are pretty weird visually.

This is a weird trick that I can’t say I 100% understand, but if you toss display: inline-block; on those boxes (and probably width: 100%; to make sure they stay column-width), then they won’t break and the padding is preserved.

Demo Quick way to make a list go horizontal

This was another mega-popular answer to my original tweet. List elements stack list items vertically, like block-level elements. They aren’t actually blocks. They are display: list-item;, which is actually somewhat important here, as we’ll see. The popular use case is “when I want to lay out a list horizontally”.

So you’ve got a list…

<ul> <li>Three</li> <li>Little</li> <li>Piggies</li> </ul>

You wanna knock it over in a row instead, you can…

li { display: inline-block; }

And you got it.

I took a quick listen in VoiceOver and the inline-block list still announces the element as a list, but doesn’t speak the bullet points, which makes sense as they aren’t there. That’s the thing with changing the display of the list items themselves away from list-item: they lose their, ahem, list-item-y-ness.

An alternative would be to make the parent a flexbox container…

ul { display: flex; }

…which achieves the horizontal row thing (the flexbox default), but leaves the bullets as you aren’t changing the display of the list items themselves. It’s on you to manually remove that if you want.

Demo Centered lists

Speaking of lists, Jeff Starr just blogged about the idea of lists within centered text, which can get awkward as well. The awkwardness is that the text inside the list items can be centered, but the list item itself is still full-width, creating this situation where the bullet stays aligned to the left.

Jeff’s solution was to inline-block the whole list. That keeps the list only as wide as the natural width of the content, allowing the bullets to leave the left edge and travel with the centered content. As long as there are block-level elements before and after, that is a good solution.

By way of an alternative, if the goal is to shrink the width of the list to the width of the content, that could also be achieved like this without stopping the list from being block-level:

ul { width: max-content; margin: 0 auto; text-align: left; }
  1. There is another tricky thing with inline-block. Like inline elements, any whitespace between them essentially renders as a space. So two 50% wide `inline-block` elements won’t fit on a line if there is any whitespace between them. Good thing there are tricks to fix that.
  2. I say “used to” because, if you were going to make a column system today, you’d almost certainly use flexbox or grid — or not build a “system” at all because just using the syntax of these largely negates the need for a system in the first place.

The post When do you use inline-block? appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Levels of Fix

Css Tricks - Mon, 07/20/2020 - 10:33am

On the web, we have the opportunity to do work that fixes things for people. It’s fascinating to me how different the scope of those fixes can be.

Consider the media query prefers-reduced-motion. Eric wrote:

I think it’s also worth pointing out the true value prefers-reduced-motion represents: Not attracting buzzword-hungry recruiters on LinkedIn, but improving the quality of life for the people who benefit from the effect it creates. Using this media query could spare someone from having to unnecessarily endure a tremendous amount of pain for simply having the curiosity to click on a link or scroll down a page.

The use of this media query is exclusively to make people’s experience on the web better. We can write code that reduces motion for users who have explicitly asked for reduced motion.

It’s worth noting that because people ask for reduced motion doesn’t mean they are asking for absolutely zero motion. But let’s set that aside for a moment. It’s probably better to err toward zero if you aren’t prepared to do the nuanced work of figuring out what level of reduction is best for your users.

So let’s say we’re going to nuke all motion for a site. We could do this:

@media (prefers-reduced-motion: reduce), (update: slow) { *, ::before, ::after { animation-delay: -1ms !important; animation-duration: 1ms !important; animation-iteration-count: 1 !important; background-attachment: initial !important; scroll-behavior: auto !important; transition-duration: 0s !important; transition-delay: 0s !important; } }

By doing that, we fix the site for all users who prefer less motion for all of those users, for one site. That’s one scope we can hit.

Another thing we could do as a web worker is build a browser extension. Miraculously, the web has a standardized format for extensions, so you can largely write it once and ship the thing to any desktop browser. When you build an extension, you can’t really force anyone to use it, and chances are that a very low percentage of people visiting your site will have it installed, even less so of those who could benefit from it. But for those that do, you’ve fixed not just one site but all sites for that one person. That’s a very different but also very interesting and powerful scope.

It’s no wonder then that some people are drawn to working on the browsers themselves. Or for the standards organizations that guide that work. I’m not saying that browsers should or would implement something like forced reduced motion at the CSS level, but they could. And if you fix something at the browsers or standards level, you might just fix something for all sites for all users, which is the biggest scope there is.

It’s these different scopes that are so interesting to me:

  • Fixing one site for all users
  • Fixing all sites for one user
  • Fixing all sites for all users

You don’t have to just pick just one. Most of us probably do most of our work in that first bucket. But it’s worth thinking about if any of your work could go towards the others.

The post Levels of Fix appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Italicize Text

Css Tricks - Fri, 07/17/2020 - 12:16pm

HTML and CSS offer us the ability to italicize text. I’m talking about text like this. Let’s cover everything you’ll need to know.

What is italic text and why would you italicize text?

You italicize text most often to call attention to it. Literally to emphasize a word, so that someone reading the sentence will give that word or phrase some extra oomph, as you might intend as the writer. Or, it might be following a particular style guide, like italicizing the title of something, say a published article.

Use the <em> tag

The “em” in <em> literally stands for emphasis. Browsers will, by default, make italicize text that is wrapped in HTML <em> tags.

<p> That was a <em>wonderful</em> party, Bebe. </p>

Imagine the sound of that sentence, where the reader is emphasizing that word giving the sentence a different feel that if they didn’t.

Use the <i> tag

The <i> element is to apply italics to text without implying emphasis. It’s to visually set some text apart from other text without implying that a reader is applying extra weight to those words. Perhaps something like:

<p><i>Miranda thought:</i> What an interesting metaphor on the global economy.</p> <p><i>Chris thought:</i> Is that mustard?</p> What’s the difference between <i> and <em>?

One more time:

  • <em> is for emphasis
  • <i> is for italic text without the emphasis

If you’re tempted to use <i> for the title of something, like:

<p> The book <!-- Not the end of the world, but... --> <i>Mr. Penumbra's 24-Hour Bookstore</i> is good. </p> <p> The book <!-- ...this is more semantically correct. --> <cite>Mr. Penumbra's 24-Hour Bookstore</cite> is good. </p>

Fortunately browsers italicize content wrapped in <cite> tags, just like <i> does, so no further work is required there if you’re citing a work (e.g. Moby Dick) or a publication (e.g. The New York Times).

Use your own HTML class and CSS

If the goal is set text apart visually, then we don’t have to reach for the <i> element. Spans have no semantic meaning and can be styled for visual emphasis:

<p> Shoes are <span class="emphasis">on sale</span> this week! </p> .emphasis { background: lightyellow; font-style: italic; }

The CSS property font-style is the one you need for making text italic, which you can apply to any selector you like.

Watch out for “Faux Italic”

Not all fonts have italicized characters. Or, you might be in a situation where the italic version of the font isn’t loaded. In either case, the browser will try to fake it anyway, which almost always looks awful (or at least much worse than using an actual italic font). 

Nothing is going to warn you about this — you kinda just need an eye for it. Here’s an example of the font Merriweather in faux italic:

CodePen Embed Fallback Unicode italics

There are a zillion characters available in Unicode, including letters that have an italic vibe.

CodePen Embed Fallback

You might use this when you don’t have HTML control to do things like italics like, say, on Twitter when composing a tweet.

The accessibility of this is awful. It will reach each character individually, making it (presumably, to me) hard to understand the word. Be very careful when using this, if you e even use it all.

Italics in variable fonts

This is a bit of an advanced concept, but there are things called variable fonts. They offer customization right in the browser. So rather than a second font file for the bold version, they have information in them to bold themselves with that one file. But “bold” is just an example of what a variable font might offer. Not all of them necessarily do.

A variable font might have a “slant” or “italic” option and you could apply that look that way.

v-fonts.com

There it is, five different answers to the question of when to italicize text. Hopefully this also helps with the next logical question: Which method should I use?

The post How to Italicize Text appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Italicize Text

Css Tricks - Fri, 07/17/2020 - 12:16pm

HTML and CSS offer us the ability to italicize text. I’m talking about text like this. Let’s cover everything you’ll need to know.

What is italic text and why would you italicize text?

You italicize text most often to call attention to it. Literally to emphasize a word, so that someone reading the sentence will give that word or phrase some extra oomph, as you might intend as the writer. Or, it might be following a particular style guide, like italicizing the title of something, say a published article.

Use the <em> tag

The “em” in <em> literally stands for emphasis. Browsers will, by default, make italicize text that is wrapped in HTML <em> tags.

<p> That was a <em>wonderful</em> party, Bebe. </p>

Imagine the sound of that sentence, where the reader is emphasizing that word giving the sentence a different feel that if they didn’t.

Use the <i> tag

The <i> element is to apply italics to text without implying emphasis. It’s to visually set some text apart from other text without implying that a reader is applying extra weight to those words. Perhaps something like:

<p><i>Miranda thought:</i> What an interesting metaphor on the global economy.</p> <p><i>Chris thought:</i> Is that mustard?</p> What’s the difference between <i> and <em>?

One more time:

  • <em> is for emphasis
  • <i> is for italic text without the emphasis

If you’re tempted to use <i> for the title of something, like:

<p> The book <!-- Not the end of the world, but... --> <i>Mr. Penumbra's 24-Hour Bookstore</i> is good. </p> <p> The book <!-- ...this is more semantically correct. --> <cite>Mr. Penumbra's 24-Hour Bookstore</cite> is good. </p>

Fortunately browsers italicize content wrapped in <cite> tags, just like <i> does, so no further work is required there if you’re citing a work (e.g. Moby Dick) or a publication (e.g. The New York Times).

Use your own HTML class and CSS

If the goal is set text apart visually, then we don’t have to reach for the <i> element. Spans have no semantic meaning and can be styled for visual emphasis:

<p> Shoes are <span class="emphasis">on sale</span> this week! </p> .emphasis { background: lightyellow; font-style: italic; }

The CSS property font-style is the one you need for making text italic, which you can apply to any selector you like.

Watch out for “Faux Italic”

Not all fonts have italicized characters. Or, you might be in a situation where the italic version of the font isn’t loaded. In either case, the browser will try to fake it anyway, which almost always looks awful (or at least much worse than using an actual italic font). 

Nothing is going to warn you about this — you kinda just need an eye for it. Here’s an example of the font Merriweather in faux italic:

CodePen Embed Fallback Unicode italics

There are a zillion characters available in Unicode, including letters that have an italic vibe.

CodePen Embed Fallback

You might use this when you don’t have HTML control to do things like italics like, say, on Twitter when composing a tweet.

The accessibility of this is awful. It will reach each character individually, making it (presumably, to me) hard to understand the word. Be very careful when using this, if you e even use it all.

Italics in variable fonts

This is a bit of an advanced concept, but there are things called variable fonts. They offer customization right in the browser. So rather than a second font file for the bold version, they have information in them to bold themselves with that one file. But “bold” is just an example of what a variable font might offer. Not all of them necessarily do.

A variable font might have a “slant” or “italic” option and you could apply that look that way.

v-fonts.com

There it is, five different answers to the question of when to italicize text. Hopefully this also helps with the next logical question: Which method should I use?

The post How to Italicize Text appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Syndicate content
©2003 - Present Akamai Design & Development.