Web Standards

Quick Tip: Debug iOS Safari on a true local emulator (or your actual iPhone/iPad)

Css Tricks - Thu, 10/11/2018 - 4:02am

We've been able to do this for years, largely for free (ignoring the costs of the computer and devices), but I'm not sure as many people know about it as they should.

TL;DR: XCode comes with a "Simulator" program you can pop open to test in virtual iOS devices. If you then open Safari's Develop/Debug menu, you can use its DevTools to inspect right there — also true if you plug in your real iOS device.

Direct Link to ArticlePermalink

The post Quick Tip: Debug iOS Safari on a true local emulator (or your actual iPhone/iPad) appeared first on CSS-Tricks.

Deliver exceptional customer experiences in your product

Css Tricks - Thu, 10/11/2018 - 3:58am

(This is a sponsored post.)

?Pendo is a product cloud that helps create lovable products that customers can’t live without. Pendo enables product teams to understand product usage, collect user feedback, measure NPS, assist users in their apps and promote new features in product — all without requiring any engineering resources. This unique combination of capabilities is all built on a common infrastructure of product data and results in better onboarding, increased user engagement, improved customer satisfaction, reduced churn, and increased revenue.

Pendo is the proven choice of innovative product leaders at Salesforce, Marketo, Zendesk, Citrix, BMC and many more leading companies.

Request a demo of Pendo today.?

Direct Link to ArticlePermalink

The post Deliver exceptional customer experiences in your product appeared first on CSS-Tricks.

The dialog element

Css Tricks - Wed, 10/10/2018 - 10:28am

Chris Manning digs into <dialog>:

A dialog element provides:

  • An element that is easy to show and hide, including an open boolean attribute on the element itself.
  • Two versions: a standard popover or modal version.
  • A ::backdrop pseudo-element for modal types.
  • Built-in focus: see dialog focusing steps.
  • ARIA role support (dialog is the implied default). Also accepts the alertdialog role.
  • A pending stack for multiple dialogs.
  • A DOM interface with the open boolean and methods show, showModal, and close.

And those are just some highlights! Showing content on top of other content has never been easier.

This is the evolution of the web at it's best. Identifying a major developer struggle and helping solve it.

Direct Link to ArticlePermalink

The post The dialog element appeared first on CSS-Tricks.

Using Event Bus to Share Props Between Vue Components

Css Tricks - Wed, 10/10/2018 - 3:44am

By default, communication between Vue components happen with the use of props. Props are properties that are passed from a parent component to a child component. For example, here’s a component where title is a prop:

<blog-post title="My journey with Vue"></blog-post>

Props are always passed from the parent component to the child component. As your application increases in complexity, you slowly hit what is called prop drilling here’s a relate article that is React-focused, but totally applies). Prop drilling is the idea of passing props down and down and down to child components — and, as you might imagine, it’s generally a tedious process.

So, tedious prop drilling can be one potential problem in a complex. The other has to do with the communication between unrelated components. We can tackle all of this by making use of an Event Bus.

What is an Event Bus? Well, it’s kind of summed up in the name itself. It’s a mode of transportation for one component to pass props from one component to another, no matter where those components are located in the tree.

Practice task: Building a counter

Let’s build something together to demonstrate the concept of an event bus. A counter that adds or subtracts a submitted value and tallies the overall total is a good place to start:

See the Pen Vuejs Event Bus Counter by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

To make use of an event bus, we first need to initialize it like so:

import Vue from 'vue'; const eventBus = new Vue();

This sets an instance of Vue to eventBus. You can name it anything you’d like, whatsoever. If you are making use of a single-file component, then you should have snippet in a separate file, since you will have to export the Vue instance assigned to eventBus anyway:

import Vue from 'vue'; export const eventBus = new Vue();

With that done, we can start making use of it in our counter component.

Here’s what we want to do:

  • We want to have a count with an initial value of 0.
  • We want an input field that accepts numeric values.
  • We want two buttons: one that will add the submitted numeric value to the count when clicked and the other to subtract that submitted numeric value from the count when clicked.
  • We want a confirmation of what happened when the count changes.

This is how the template looks with each of those elements in place:

<div id="app"> <h2>Counter</h2> <h2>{{ count }}</h2> <input type="number" v-model="entry" /> <div class="div__buttons"> <button class="incrementButton" @click.prevent="handleIncrement"> Increment </button> <button class="decrementButton" @click.prevent="handleDecrement"> Decrement </button> </div> <p>{{ text }}</p> </div>

We bind the input field to a value called entry, which we’ll use to either increase or decrease the count, depending on what is entered by the user. When either button is clicked, we trigger a method that should either increase or decrease the value of count. Finally, that {{ text }} thing contained in <p> tag is the message we’ll print that summarizes the change to the count.

Here’s how that all comes together in our script:

new Vue({ el: '#app', data() { return { count: 0, text: '', entry: 0 } }, created() { eventBus.$on('count-incremented', () => { this.text = `Count was increased` setTimeout(() => { this.text = ''; }, 3000); }) eventBus.$on('count-decremented', () => { this.text = `Count was decreased` setTimeout(() => { this.text = ''; }, 3000); }) }, methods: { handleIncrement() { this.count += parseInt(this.entry, 10); eventBus.$emit('count-incremented') this.entry = 0; }, handleDecrement() { this.count -= parseInt(this.entry, 10); eventBus.$emit('count-decremented') this.entry = 0; } } })

You may have noticed that we’re about to hop on the event bus by looking at that code.

First thing we’ve got to do is establish a path for sending an event from one component to another. We can pave that path using eventBus.$emit() (with emit being a fancy word for sending out). That sending is included in two methods, handleIncrement and handleDecrement, which is listening for the input submissions. And, once they happen, our event bus races to any component requesting data and sends the props over.

You may have noticed that we are listening for both events in the created() lifecycle hook using eventBus.$on(). In both events, we have to pass in the string that corresponds to the event we emitted. This is like an identifier for the particular event and the thing that established a way for a component to receive data. When eventBus recognizes a particular event that has been announced, the function that follows is called — and we set a text to display what had happened, and make it it disappear after three seconds.

Practice task: Handling multiple components

Let’s say we are working on a profile page where users can update their name and email address for an app and then see the update without refreshing the page. This can be achieved smoothly using event bus, even though we are dealing with two components this time: the user profile and the form that submits profile changes.

See the Pen Vuejs Event Bus 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Here is the template:

<div class="container"> <div id="profile"> <h2>Profile</h2> <div> <p>Name: {{name}}</p> <p>Email: {{ email }}</p> </div> </div> <div id="edit__profile"> <h2>Enter your details below:</h2> <form @submit.prevent="handleSubmit"> <div class="form-field"> <label>Name:</label> <input type="text" v-model="user.name" /> </div> <div class="form-field"> <label>Email:</label> <input type="text" v-model="user.email" /> </div> <button>Submit</button> </form> </div> </div>

We will pass the ids (user.name and user.email)to the corresponding component. First, let’s set up the template for the Edit Profile (edit__profile) component, which holds the name and email data we want to pass to the Profile component we’ll set up next. Again, we’ve established an event bus to emit that data after it detects that a submission event has taken place.

new Vue({ el: "#edit__profile", data() { return { user: { name: '', email: '' } } }, methods: { handleSubmit() { eventHub.$emit('form-submitted', this.user) this.user = {} } } })

This data will be used to reactively update the profile on the user in the Profile (profile) component, which looking for name and email to come in when the bus arrives to its hub.

new Vue({ el: '#profile', data() { return { name: '', email: '' } }, created() { eventHub.$on('form-submitted', ({ name, email}) => { this.name = name; this.email = email }) } })

Their bags are packed. Now all they have to do is go home.

Pretty cool, right? Even though the Edit Profile and Profile components are unrelated — or not in a direct parent-child relationship) — it is possible for them to communicate with each other, linked by the same event.

Rollin’ right along

I have found Event Bus helpful in cases where I want to enable reactivity in my app — specifically, to update a component based on the response obtained from the server without causing the page to refresh. It is also possible that the event that gets emitted can be listened to by more than one component.

If you have other interesting scenarios of using event bus, I’ll love to hear about them in the comments. &#x1f68c;

The post Using Event Bus to Share Props Between Vue Components appeared first on CSS-Tricks.

What are Durable Functions?

Css Tricks - Tue, 10/09/2018 - 3:55am

Oh no! Not more jargon! What exactly does the term Durable Functions mean? Durable functions have to do with Serverless architectures. It’s an extension of Azure Functions that allow you to write stateful executions in a serverless environment.

Think of it this way. There are a few big benefits that people tend to focus on when they talk about Serverless Functions:

  • They’re cheap
  • They scale with your needs (not necessarily, but that’s the default for many services)
  • They allow you to write event-driven code

Let’s talk about that last one for a minute. When you can write event-driven code, you can break your operational needs down into smaller functions that essentially say: when this request comes in, run this code. You don’t mess around with infrastructure, that’s taken care of for you. It’s a pretty compelling concept.

In this paradigm, you can break your workflow down into smaller, reusable pieces which, in turn, can make them easier to maintain. This also allows you to focus on your business logic because you’re boiling things down to the simplest code you need run on your server.

So, here’s where Durable Functions come in. You can probably guess that you’re going to need more than one function to run as your application grows in size and has to maintain more states. And, in many cases, you’ll need to coordinate them and specify the order in which they should be run for them to be effective. It's worth mentioning at this point that Durable Functions are a pattern available only in Azure. Other services have variations on this theme. For example, the AWS version is called Step Functions. So, while we're talking about something specific to Azure, it applies more broadly as well.

Durable in action, some examples

Let’s say you’re selling airline tickets. You can imagine that as a person buys a ticket, we need to:

  1. check for the availability of the ticket
  2. make a request to get the seat map
  3. get their mileage points if they’re a loyalty member
  4. give them a mobile notification if the payment comes through and they have an app installed/have requested notifications

(There’s typically more, but we’re using this as a base example)

Sometimes these will all run be run concurrently, sometimes not. For instance, let’s say they want to purchase the ticket with their mileage rewards. Then you’d have to first check the awards, and then the availability of the ticket. And then do some dark magic to make sure no customers, even data scientists, can actually understand the algorithm behind your rewards program.

Orchestrator functions

Whether you’re running these functions at the same moment, running them in order, or running them according to whether or not a condition is met, you probably want to use what’s called an orchestrator function. This is a special type of function that defines your workflows, doing, as you might expect, orchestrating the other functions. They automatically checkpoint their progress whenever a function awaits, which is extremely helpful for managing complex asynchronous code.

Without Durable Functions, you run into a problem of disorganization. Let’s say one function relies on another to fire. You could call the other function directly from the first, but whoever is maintaining the code would have to step into each individual function and keep in their mind how it’s being called while maintaining them separately if they need changes. It's pretty easy to get into something that resembles callback hell, and debugging can get really tricky.

Orchestrator functions, on the other hand, manage the state and timing of all the other functions. The orchestrator function will be kicked off by an orchestration trigger and supports both inputs and outputs. You can see how this would be quite handy! You’re managing the state in a comprehensive way all in one place. Plus, the serverless functions themselves can keep their jobs limited to what they need to execute, allowing them to be more reusable and less brittle.

Let’s go over some possible patterns. We’ll move beyond just chaining and talk about some other possibilities.

Pattern 1: Function chaining

This is the most straightforward implementation of all the patterns. It's literally one orchestrator controlling a few different steps. The orchestrator triggers a function, the function finishes, the orchestrator registers it, and then then next one fires, and so on. Here's a visualization of that in action:

See the Pen Durable Functions: Pattern #1- Chaining by Sarah Drasner (@sdras) on CodePen.

Here's a simple example of that pattern with a generator.

const df = require("durable-functions") module.exports = df(function*(ctx) { const x = yield ctx.df.callActivityAsync('fn1') const y = yield ctx.df.callActivityAsync('fn2', x) const z = yield ctx.df.callActivityAsync('fn3', y) return yield ctx.df.callActivityAsync('fn3', z) })

I love generators! If you're not familiar with them, check out this great talk by Bodil on the subject).

Pattern 2: Fan-out/fan-in

If you have to execute multiple functions in parallel and need to fire one more function based on the results, a fan-out/fan-in pattern might be your jam. We'll accumulate results returned from the functions from the first group of functions to be used in the last function.

See the Pen Durable Functions: Pattern #2, Fan Out, Fan In by Sarah Drasner (@sdras) on CodePen.

const df = require('durable-functions') module.exports = df(function*(ctx) { const tasks = [] // items to process concurrently, added to an array const taskItems = yield ctx.df.callActivityAsync('fn1') taskItems.forEach(item => tasks.push(ctx.df.callActivityAsync('fn2', item)) yield ctx.df.task.all(tasks) // send results to last function for processing yield ctx.df.callActivityAsync('fn3', tasks) }) Pattern 3: Async HTTP APIs

It's also pretty common that you'll need to make a request to an API for an unknown amount of time. Many things like the distance and amount of requests processed can make the amount of time unknowable. There are situations that require some of this work to be done first, asynchronously, but in tandem, and then another function to be fired when the first few API calls are completed. Async/await is perfect for this task.

See the Pen Durable Functions: Pattern #3, Async HTTP APIs by Sarah Drasner (@sdras) on CodePen.

const df = require('durable-functions') module.exports = df(async ctx => { const fn1 = ctx.df.callActivityAsync('fn1') const fn2 = ctx.df.callActivityAsync('fn2') // the responses come in and wait for both to be resolved await fn1 await fn2 // then this one this one is called await ctx.df.callActivityAsync('fn3') })

You can check out more patterns here! (Minus animations. &#x1f609;)

Getting started

If you'd like to play around with Durable Functions and learn more, there's a great tutorial here, with corresponding repos to fork and work with. I'm also working with a coworker on another post that will dive into one of these patterns that will be out soon!

Alternative patterns

Azure offers a pretty unique thing in Logic Apps, which allows you the ability to design workflows visually. I'm usually a code-only-no-WYSIWYG lady myself, but one of the compelling things about Logic Apps is that they have readymade connectors with services like Twilio and SendGrid, so that you don't have to write that slightly annoying, mostly boilerplate code. It can also integrate with your existing functions so you can abstract away just the parts connect to middle-tier systems and write the rest by hand, which can really help with productivity.

The post What are Durable Functions? appeared first on CSS-Tricks.

Unbuttoning Buttons

Css Tricks - Mon, 10/08/2018 - 10:21am

We dug into overriding default buttons styles not long ago here on CSS-Tricks. With garden-variety fully cross-browser-supported styles, you're looking at 6-10 CSS rules to tear down anything you need to off a button and then put in place your own styles. Hardly a big deal if you ask me, especially since it's extremely likely you'll be styling buttons anyway.

Scott O'Hara has taken a look as well. I think the solution offered to use a <span role="button" tabindex="0" onClick="..."> is a little bizarre since you need bring your own keyboard handling with is non-trivial and requires JavaScript. But there are a couple of interesting other CSS explorations, neither of which stacked up for different reasons:

  • display: contents; - some semantics-based accessibility problems.
  • all: unset; - doesn't reset display value, not good enough browser support.

Direct Link to ArticlePermalink

The post Unbuttoning Buttons appeared first on CSS-Tricks.

Using Recompose to Share Functionality Between React Components

Css Tricks - Mon, 10/08/2018 - 3:46am

Sharing functionality between React components is a pretty common need. The concept is that we can establish the behavior in one place and then extend it across different components. Higher-Order Components are one way to do this. Yet, there is another way using a library called Recompose.

GitHub Repo

What is Recompose?

The documentation helps us answer that:

Recompose is a React utility belt for function components and higher-order components. Think of it like lodash for React.

Basically, it’s a library for React that contains a bunch of helpers that return different higher-order components — which is nice because it takes some of the grunt work out of defining common React patterns and making them immediately available to extend to other components.

What exactly can it do? Well, let’s walk through a few examples together.

Add state to functional stateless components

If you couldn’t guess it by the name, a functional stateless component does not have any states. It merely accepts props and returns UI to the front end.

const Greeting = props => <p> Hello, {props.name}! </p>

In scenarios where you want to make use of state in your functional stateless component, you have to convert it to a class component. This is where Recompose comes in handy.

Recompose provides you with the withState() helper to add state to your functional stateless components. It manages a single state value. You cannot manage more than one state value in withState() like you will do in your class component. You pass in a function to update the state value and an optional default stated value.

Here’s how withState() is structured:

withState( stateName: string, // the name we call our state stateUpdaterName: string, // the name of the function to call initialState: any | (props: Object) => any // optional default state to pass ): HigherOrderComponent

A counter is a common example that’s used to demonstrate a concept. Here’s how we can create a super simple counter using Recompose’s withState() helper:

const App = withState("count", "handleCounter", 0)(({ count, handleCounter }) => { return ( <div> <p>{count}</p> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> ); });

Since the withState() helper is already available to us, we can call it right away and provide it with the parameters it needs. Again, those are:

  • stateName: The name we call our state
  • stateUpdaterName: The name of the function to call
  • initialState: Optional default state to pass

Those parameters are then integrated into the UI markup we want to render on the front end.

There’s another way we could have made our counter component and it’s worth looking at to get more practice putting a Recompose helper to use.

First, we create a higher-order component using withState() and the required parameters.

const enhanced = withState("counter", "handleCounter", 0);

Next, we make the Counter component, working in the withState() parameters:

const Counter = ({ counter, handleCounter }) => ( <div> <h1>{counter}</h1> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> );

Note that the name of the state and updater function is passed as props to the Counter component.

Finally, we create our App component by wrapping the Counter component in the higher-order enhanced component.

const App = enhanced(Counter);

See the Pen Recompose withState by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Here is another popular approach:

const enhanced = withState("count", "handleCounter", 0); const App = enhanced(({ count, handleCounter }) => { return ( <div> <p>{count}</p> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> ); });

See the Pen Recompose withState v2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Handle state using withHandlers()

Recompose also has a withHandlers() helper that allows you handle state by defining functions that will be used to update a component’s state. And, you can use it right alongside withState()!

These are basically higher-order functions that take in props and return a function handler. Let’s break down the structure like we did in the previous example.

withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); } })

First off, we’ve identified incrementCounter, which will be available to our Counter component to update the count value on click.

Next, we construct the counter like we did before — as a higher-order component using withState():

const enhancedState = withState("count", "handleCounter", 0);

Now, we define our functions putting withHandlers() to use:

const enhancedHandler = withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); }, decrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count - 1); } });

We’ve constructed a higher-order component we’re calling enhancedHandler and used withState() to define two function handlers in it: incrementCounter and decrementCounter. These handlers contain parameters that will be received as props by the components that call them. They will be needed if we want to update the state of the component defined using withState().

Alright, on to creating our counter component:

const Counter = ({ count, incrementCounter, decrementCounter }) => ( <div> <h1>{count}</h1> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> );

See that? The state and handlers are expected to be passed as props to the counter component.

To make use of the higher-order components we defined, we have to pass the Counter component to enhancedHandler and wrap that as a parameter to enhancedState.

In other words:

const App = enhancedState(enhancedHandler(Counter));

See the Pen Recompose withState & withHandlers by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Composing multiple higher-order components

In that last example, we made use of two higher-order components. Is there a better of chaining them together? Most definitely! Recompose provides us with a compose() helper to do exactly that. We can use compose() to create a component that composes both higher-order components in one fell swoop.

const enhanced = compose( withState("count", "handleCounter", 0), withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); }, decrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count - 1); } }) );

Now, we can use the enhanced component in our App component:

const App = enhanced(({ count, incrementCounter, decrementCounter }) => { return ( <div> <p>{count}</p> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> ); });

See the Pen Recompose - compose withState & withHandlers by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Manage state using Redux like reducer

Another nice thing Recompose does is allow you to manage state using a reducer function (withReducer). A reducer updates the state of a component in response to a particular action.

The structure of the withReducer() looks like this:

withReducer<S, A>( stateName: string, dispatchName: string, reducer: (state: S, action: A) => S, initialState: S | (ownerProps: Object) => S ): HigherOrderComponent</S>

The first parameter is the name of the state. The second is the dispatch method. dispatch will be used in dispatching actions like we have in Redux. Next, we have the reducer and the initial state.

In the context of our counter component, withReducer() will update the state of the count: the count will go up with an action we’ll call increment and, conversely, the count will go down with an action we’ll call decrement.

First, we create an enhanced component by composing withReducer and withHandlers.

const enhanced = compose( withReducer( "count", "dispatch", (state, action) => { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } }, 0 ), withHandlers({ incrementCounter: ({ dispatch }) => e => dispatch({ type: "INCREMENT" }), decrementCounter: ({ dispatch }) => e => dispatch({ type: "DECREMENT" }) }) );

incrementCounter and decrementCounter will respond to DOM events and dispatch an action type. The state will be updated depending on the action type. Next, we need to make use of this in our component.

const App = enhanced(({ count, incrementCounter, decrementCounter }) => { return ( <div> <p>{count}</p> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> ); });

See the Pen Recompose - reducer by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Pretty neat, right?

Hopefully this gives you a good idea of what Recompose is and how the library’s wealth of helpers can streamline React development, particularly when it comes to managing and calling states.

Naturally, there’s a lot more to Recompose than what we’ve covered here. A quick scan of the API documentation will show that there are many higher-order components that you can put to use, depending on your application’s requirements. Go forth, build, and please feel free to drop a comment in if you have any questions!

The post Using Recompose to Share Functionality Between React Components appeared first on CSS-Tricks.

Material Design Animation Guides

Css Tricks - Fri, 10/05/2018 - 12:53pm

I've seen two guides posted to Medium about animation in the last month that have seriously blown up!

There is a lot to learn in each one! The demonstration animations they use are wonderfully well done and each guide demonstrates an interesting and effective animation technique, often paired next to a less successful technique to drive the point home. They are both heavily focused on Material Design though, which is fine, but I think Val Head said it best:

Google wrote material design for branding Google things. When you use material design on things that aren’t Google, you’re kind of using Google’s branding on a thing that is not Google, and that’s weird. Material design is Google’s opinion on motion. It’s Google’s branding opinion on motion. It’s not a de facto standard of how motion should happen.

The post Material Design Animation Guides appeared first on CSS-Tricks.

One Invalid Pseudo Selector Equals an Entire Ignored Selector

Css Tricks - Fri, 10/05/2018 - 3:45am

Perhaps you know this one: if any part of a selector is invalid, it invalidates the whole selector. For example:

div, span::butt { background: red; }

Even though div is a perfectly valid selector, span:butt is not, thus the entire selector is invalidated — neither divs nor span::butt elements on the page will have a red background.

Normally that's not a terribly huge problem. It may even be even useful, depending on the situation. But there are plenty of situations where it has kind of been a pain in the, uh, :butt.

Here's a classic:

::selection { background: lightblue; }

For a long time, Firefox didn't understand that selector, and required a vendor prefix (::-moz-selection) to get the same effect. (This is no longer the case in Firefox 62+, but you take the point.)

In other words, this wasn't possible:

/* would break for everyone */ ::selection, ::-moz-selection { background: lightblue; }

That would break for browsers that understood ::selection and break for Firefox that only understood ::-moz-selection. It made it ripe territory for a preprocessor @mixin, that's for sure.

That was annoying enough that browsers have apparently fixed it. In a conversation with Estelle Weyl, I learned that this is being changed. She wrote in the MDN docs:

Generally, if there is an invalid pseudo-element or pseudo-class within in a chain or group of selectors, the whole selector list is invalid. If a pseudo-element (but not pseudo-class) has a -webkit- prefix, As of Firefox 63, Blink, Webkit and Gecko browsers assume it is valid, not invalidating the selector list.

This isn't for any selector; it's specifically for pseudo-elements. That is, double colons (::).

Here's a test:

See the Pen Ignored Invalid Selecotrs??? by Chris Coyier (@chriscoyier) on CodePen.

I'd call that a positive change.

The post One Invalid Pseudo Selector Equals an Entire Ignored Selector appeared first on CSS-Tricks.

CSS Only Floated Labels with :placeholder-shown pseudo class

Css Tricks - Thu, 10/04/2018 - 8:08am

The floated label technique has been around for a good long while and the general idea is this: we have an text input with the placeholder attribute acting as a label. When a user types into that input, the label moves from inside the input to outside of it.

Like so:

Although I don’t see this pattern used on the web all that much, I do think it’s an interesting one! There are different approaches to it, but Nick Salloum describes a new one using a combination of :not and :placeholder-shown:

This UI technique does indeed slightly bend the definitions of label and placeholder listed above, in the sense that we’re giving the placeholder more initial importance in having to explain the input to the user, but it’s a tradeoff for a neat UI component, and one that I’m personally comfortable making.

I wonder if there are other peculiar ways :not and :placeholder-shown could be put to use.

Direct Link to ArticlePermalink

The post CSS Only Floated Labels with :placeholder-shown pseudo class appeared first on CSS-Tricks.

Moving Backgrounds With Mouse Position

Css Tricks - Thu, 10/04/2018 - 4:04am

Let's say you wanted to move the background-position on an element as you mouse over it to give the design a little pizzazz. You have an element like this:

<div class="module" id="module"></div>

And you toss a background on it:

.module { background-image: url(big-image.jpg); }

You can adjust the background-position in JavaScript like this:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.backgroundPositionX = -e.offsetX + "px"; el.style.backgroundPositionY = -e.offsetY + "px"; });

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Or, you could update CSS custom properties in the JavaScript instead:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.setProperty('--x', -e.offsetX + "px"); el.style.setProperty('--y', -e.offsetY + "px"); }); .module { --x: 0px; --y: 0px; background-image: url(large-image.jpg); background-position: var(--x) var(--y); }

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Here's an example that moves the background directly in JavaScript, but with a transition applied so it slides to the new position rather than jerking around the first time you enter:

See the Pen Movable Background Ad by Chris Coyier (@chriscoyier) on CodePen.

Or, you could move an actual element instead (rather than the background-position). You'd do this if there is some kind of content or interactivity on the sliding element. Here's an example of that, which sets CSS custom properties again, but then actually moves the element via a CSS translate() and a calc() to temper the speed.

See the Pen Hotjar Moving Heatmap Ad by Chris Coyier (@chriscoyier) on CodePen.

I'm sure there are loads of other ways to do this — a moving SVG viewBox, scripts controlling a canvas, webGL... who knows! If you have some fancier ways to handle this, link 'em up in the comments.

The post Moving Backgrounds With Mouse Position appeared first on CSS-Tricks.

The industry’s best open API

Css Tricks - Thu, 10/04/2018 - 4:02am

(This is a sponsored post.)

With our robust SDK, super clean dashboard, detailed documentation, and world-class support, HelloSign API is one of the most flexible and powerful APIs on the market. Start building for free today.

Direct Link to ArticlePermalink

The post The industry’s best open API appeared first on CSS-Tricks.

The Codification of Design

Css Tricks - Wed, 10/03/2018 - 12:20pm

Jonathan Snook on managing the complexity between what designers make and what developers end up building:

Everything that a designer draws in a Sketch or Photoshop file needs to be turned into code. Code needs to be developed, delivered to the user, and maintained by the team.

That means that complexity in design can lead to complexity in code.

That’s not to say that complexity isn’t allowed. However, it is important to consider what the impact of that complexity is—especially as it relates to your codebase.

Jonathan continues in that post to argue that designers and developers need to be in a constant feedback loop in order to properly assess whether the complexity of the design is worth the complexity of the engineering solution.

I’ve been thinking about this sort of thing for a really long time as it applies to my work in design systems — I have a feeling this issue stems from the fact that designers and developers are trading with different currencies. Designers generally care about the user experience above anything else while developers may prioritize the code under the hood, willing to over-engineer something for this one tiny detail.

As Snook mentions later in his post, pattern libraries won’t solve this problem entirely:

This is why it’s important to have these conversations during the design process. It’s important to understand what the priorities are within your team. It’s important to understand what tradeoffs you’re willing to make. Without consensus within your team, you’ll continue to butt heads as the requirements of the front-end development team conflict with the requirements of the design team.

So, the best way to get those two groups to exchange the same currency is with talking, instead of tools. Or, perhaps by designing with code.

Direct Link to ArticlePermalink

The post The Codification of Design appeared first on CSS-Tricks.

How Do You Put a Border on Three Sides of an Element?

Css Tricks - Wed, 10/03/2018 - 6:12am

I saw a little conversation about this the other day and figured it would be fun to look at all the different ways to do it. None of them are particularly tricky, but perhaps you'll favor one over another for clarity of syntax, efficiency, or otherwise.

Let's assume we want a border on the bottom, left, and right (but not top) of an element.

Explicitly declare each side .three-sides { border-bottom: 2px solid black; border-right: 2px solid black; border-left: 2px solid black; }

While that's pretty clear, it's still making use of shorthand. Completely expanded it would be like this:

.three-sides { border-bottom-color: black; border-bottom-style: solid; border-bottom-width: 2px; border-left-color: black; border-left-style: solid; border-left-width: 2px; border-right-color: black; border-right-style: solid; border-right-width: 2px; } Knock off one of the sides

You can save a little code by declaring the border on all four sides with shorthand and then removing the one you don't want:

.three-sides { border: 2px solid black; border-top: 0; } Shorthand just the width .three-sides { border-color: black; border-style: solid; /* top, right, bottom, left - just like margin and padding */ border-width: 0 2px 2px 2px; }

As a fun little aside here, you don't need to declare the border color to get a border to show up, because the color will inherit the currentColor! So this would work fine:

.three-sides { /* no color declared */ border-style: solid; border-width: 0 2px 2px 2px; }

And you'd have red borders if you did:

.three-sides { border-color: red; border-style: solid; border-width: 0 2px 2px 2px; }

Strange, but true.

If you want to add the color explicity, you can kinda mix-and-match shorthand, so this will work fine:

.three-sides { border: solid green; border-width: 2px 0 2px 2px; }

The post How Do You Put a Border on Three Sides of an Element? appeared first on CSS-Tricks.

Product Adoption 101 – A Primer For UX And Product Teams [Sponsored]

Usability Geek - Wed, 10/03/2018 - 6:10am
?Software companies are naturally excited when they go to roll out a new product or feature. And in a perfect world, that product/feature is immediately, and enthusiastically adopted by every...
Categories: Web Standards

Selectors That Depend on Layout

Css Tricks - Tue, 10/02/2018 - 12:44pm

"Why the heck don't we have ::first-column?"

I heard someone ask that the other day and it's a valid question. I'd even take that question further by asking about ::nth-column() or whatever else relates to CSS columns. We have stuff like ::first-letter and ::first-line. Why not others?

There are many notable things missing from the "nth" crowd. Seven years ago, I wrote "A Call for ::nth-everything" and it included clear use cases like, perhaps, selecting the first two lines of a paragraph.

I don't know all the technical details of it all, but I know there are some fairly decent reasons why we don't have all of these in CSS. Part of it is the difficulty of getting it specced (e.g. words and characters get tricky across written languages) and part of it is the difficulty of implementing them. What I just found out is that there is a FAQ document that explains!

So, why don't we have ::first-column? Because it's a "selector that depends on layout":

This falls into a class of problems that unlikely to be solvable in CSS: selectors in general, and pseudo classes in particular, cannot depend on layout, because otherwise they could be used to modify layout in a way that made them no longer match, which would modify the layout back to where it was, so they match again, and we get stuck in an infinite loop of contradictions.

For a simple example:

:stuck { position: static; }

Now what?

Some of the changes web developers might want to apply with a :stuck pseudo class may be safe and not trigger such loops, but selectors are a generic mechanism, and would enable this kind of contradictions.

So even though many of the problem people are trying to address using such pseudo classes are legitimate, selectors are unlikely to be the answer.

What we've got are infinite loops that are basically the problem (but read the FAQ — it goes into great detail about the nuance of it). In a related way, the same reason we don't have element queries in CSS.

It's a little tricky to think about because even stuff like ::first-line are riddled with paradoxes. Say you use it to increase the font-size. That means fewer characters fit on the line, so the characters that originally matched are now pushed down and don't match anymore. Seems a bit loopy, but that's been sorted out. Plus, classics like :hover potentially causing jitter. The document talks about these things in clear terms. It's not all cut and dry!

The whole FAQ is a fascinating read and covers much more than this situation.

Direct Link to ArticlePermalink

The post Selectors That Depend on Layout appeared first on CSS-Tricks.

Apply a Filter to a Background Image

Css Tricks - Tue, 10/02/2018 - 4:06am

You can apply a filter to an entire element quite easily with the filter property. But what if you want to apply a filter just to the background of an element? It's weirdly tricky.

There are CSS properties that specific to backgrounds, like background-blend-mode — but blending and filters are not the same thing. It sorta seems to be the reason we have backdrop-filter, but not quite. That does filtering as the background interacts with what is behind the element.

There is no background-filter, unfortunately. What are we to do?

Use a pseudo-element instead of a background

If you put the contents of the element in an inside wrapper, you can set that on top of a pseudo-element that is simply pretending to be a background.

.module { position: relative; } .module::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: url(graphic-to-be-filtered.jpg); filter: grayscale(100%); } .module-inside { /* This will make it stack on top of the ::before */ position: relative; }

See the Pen Apply Filter to Psuedo Element by Chris Coyier (@chriscoyier) on CodePen.

See how the "background" gets filtered with grayscale there? We called the grayscale filter there and applied it only to the pseudo-element, leaving the rest of the content inside unfiltered.

It depends on what kind of filtering you want... you might be able to fake it with blend modes

I ran into this issue as I was specifically trying to grayscale the background image of an element. Since, as we've covered, there is no specific property just for that, I thought about background-blend-mode, particularly how there are blending options for things like saturation and color. If I could set pure black over the top of the graphic, then I could blend them — like I can with multiple backgrounds — and essentially fake a grayscale effect.

Note that you can't use a solid color by itself when working with multiple backgrounds (that would be a background-color not background-image), so we have to fake that as well with a no-transition linear-gradient.

.module { background-image: linear-gradient(black, black), url(image-to-be-fake-filters.jpg); background-size: cover; background-blend-mode: saturation; }

See the Pen Apply Fake Filter with Blend Mode by Chris Coyier (@chriscoyier) on CodePen.

Dan Wilson's explorations

Dan got way into this and made an exploratory Pen in which there are three layers:

  1. Top layer: a vignette from a radial-gradient
  2. Middle layer: solid color
  3. Bottom layer: image graphic

You can adjust the colors used on the top two layers and apply different blend modes to each one. That was another thing I learned! Just like you can comma-separate to make multiple backgrounds (and likewise with background-size, background-position and such to apply those values to specific backgrounds) you can also comma-separate background-blend-mode to apply different blending effects to each layer.

See the Pen Multiple Backgrounds, Multiple Blend Modes by Dan Wilson (@danwilson) on CodePen.

The post Apply a Filter to a Background Image appeared first on CSS-Tricks.

Netlify

Css Tricks - Tue, 10/02/2018 - 4:06am

(This is a sponsored post.)

It's always fun to watch developers discover Netlify for the first time. It's so easy. One way to do it is to just literally drag and drop a folder onto them and it will be online. Even better, connect a Git repo to a Netlify site and tell it what branch you want to watch, then any commits to that branch will automatically go live, even running your site's build as it does it. I heard one developer say, "It's like someone actually designed hosting and deployment."

That lends itself nicely to static sites, but don't think that static sites are only for certain types of sites or limiting in some way. That's what the JAMstack is all about! Wanna learn more about that? Come to JAMstack_conf!

Netlify does a ton to help you power your JAMstack site as well. They'll process your forms. They'll help you with authentication. They'll do your A/B testing. They'll even run your cloud functions. Pretty incredible, really.

Direct Link to ArticlePermalink

The post Netlify appeared first on CSS-Tricks.

Preventing a Grid Blowout

Css Tricks - Mon, 10/01/2018 - 11:17am

Say you have a very simple CSS grid layout with one column fixed at 300px and another taking up the rest of the space at 1fr.

.grid { display: grid; grid-template-columns: 1fr 300px; }

That's somewhat robust. That 1fr column will take up any remaining space left behind by the fixed 300px column. It's true that the auto value would do the same, but auto isn't quite as robust since it's size is based on the content inside. So, if you had too little content, then your column might not fill the entire space you want it to. But while 1fr is slightly more robust, it won't quite protect you from content that is too big!

Here's the grid behaving just fine with some text content:

Now, watch that right column get blown off the page when we drop a gigantic image in that column:

That one is easy to fix — and you may never even have it happen to you, because this snippet is so common in our stylesheets:

img { max-width: 100%; }

But some elements aren't so friendly. Take the notorious <pre> tag. Say we toss one of those in our 1fr column with a long string of text. We're back to wrecked:

This time, things aren't so easily fixed! Even attempting to limit the width and hide the overflow of <pre> isn't going to help:

pre { max-width: 100%; overflow: hidden; }

The real fix isn't all that difficult — we only need to understand what is happening. I can't promise I'm explaining this 100% accurately, but the way I understand it, the minimum width of a grid column is auto. (The same is true for flex items, by the way.)

And since auto is entirely based on content, we can say it is "indefinitely" sized, its dimensions flex. If we were to put an explicit width on the column, like 50% or 400px, then we would say it is "definitely" sized.

To apply our fix, we need to make sure that there is the column has a definite minimum width instead of auto.

So, we can either fix it like this:

.grid { /* auto minimum width, causing problem */ grid-template-columns: 1fr 300px; /* fix: minimum width of 0 */ grid-template-columns: minmax(0, 1fr) 300px; }

Or, we put an actual min-width on the element that occupies that grid column. In our simple demo, the <main> element automatically places itself in that first column as it is the first child of the grid.

That give us this:

main { min-width: 0; }

I think it's a bit more robust to do this at the grid definition level. Anyway, it does the trick! See how the <pre> tag now respects the width of the column and can overflow as expected?

Nice.

The post Preventing a Grid Blowout appeared first on CSS-Tricks.

The Shapes of CSS

Css Tricks - Mon, 10/01/2018 - 4:05am

CSS is capable of making all sorts of shapes. Squares and rectangles are easy, as they are the natural shapes of the web. Add a width and height and you have the exact size rectangle you need. Add border-radius and you can round that shape, and enough of it you can turn those rectangles into circles and ovals.

We also get the ::before and ::after psuedo elements in CSS, which give us the potential of two more shapes we can add to the original element. By getting clever with positioning, transforming, and many other tricks, we can make lots of shapes in CSS with only a single HTML element.

Square #square { width: 100px; height: 100px; background: red; } Rectangle #rectangle { width: 200px; height: 100px; background: red; } Circle #circle { width: 100px; height: 100px; background: red; border-radius: 50% } Oval #oval { width: 200px; height: 100px; background: red; border-radius: 100px / 50px; } Triangle Up #triangle-up { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid red; } Triangle Down #triangle-down { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-top: 100px solid red; } Triangle Left #triangle-left { width: 0; height: 0; border-top: 50px solid transparent; border-right: 100px solid red; border-bottom: 50px solid transparent; } Triangle Right #triangle-right { width: 0; height: 0; border-top: 50px solid transparent; border-left: 100px solid red; border-bottom: 50px solid transparent; } Triangle Top Left #triangle-topleft { width: 0; height: 0; border-top: 100px solid red; border-right: 100px solid transparent; } Triangle Top Right #triangle-topright { width: 0; height: 0; border-top: 100px solid red; border-left: 100px solid transparent; } Triangle Bottom Left #triangle-bottomleft { width: 0; height: 0; border-bottom: 100px solid red; border-right: 100px solid transparent; } Triangle Bottom Right #triangle-bottomright { width: 0; height: 0; border-bottom: 100px solid red; border-left: 100px solid transparent; } Curved Tail Arrow via Ando Razafimandimby #curvedarrow { position: relative; width: 0; height: 0; border-top: 9px solid transparent; border-right: 9px solid red; transform: rotate(10deg); } #curvedarrow:after { content: ""; position: absolute; border: 0 solid transparent; border-top: 3px solid red; border-radius: 20px 0 0 0; top: -12px; left: -9px; width: 12px; height: 12px; transform: rotate(45deg); } Trapezoid #trapezoid { border-bottom: 100px solid red; border-left: 25px solid transparent; border-right: 25px solid transparent; height: 0; width: 100px; } Parallelogram #parallelogram { width: 150px; height: 100px; transform: skew(20deg); background: red; } Star (6-points) #star-six { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid red; position: relative; } #star-six:after { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-top: 100px solid red; position: absolute; content: ""; top: 30px; left: -50px; } Star (5-points) via Kit MacAllister #star-five { margin: 50px 0; position: relative; display: block; color: red; width: 0px; height: 0px; border-right: 100px solid transparent; border-bottom: 70px solid red; border-left: 100px solid transparent; transform: rotate(35deg); } #star-five:before { border-bottom: 80px solid red; border-left: 30px solid transparent; border-right: 30px solid transparent; position: absolute; height: 0; width: 0; top: -45px; left: -65px; display: block; content: ''; transform: rotate(-35deg); } #star-five:after { position: absolute; display: block; color: red; top: 3px; left: -105px; width: 0px; height: 0px; border-right: 100px solid transparent; border-bottom: 70px solid red; border-left: 100px solid transparent; transform: rotate(-70deg); content: ''; } Pentagon #pentagon { position: relative; width: 54px; box-sizing: content-box; border-width: 50px 18px 0; border-style: solid; border-color: red transparent; } #pentagon:before { content: ""; position: absolute; height: 0; width: 0; top: -85px; left: -18px; border-width: 0 45px 35px; border-style: solid; border-color: transparent transparent red; } Hexagon #hexagon { width: 100px; height: 55px; background: red; position: relative; } #hexagon:before { content: ""; position: absolute; top: -25px; left: 0; width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 25px solid red; } #hexagon:after { content: ""; position: absolute; bottom: -25px; left: 0; width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-top: 25px solid red; } Octagon #octagon { width: 100px; height: 100px; background: red; position: relative; } #octagon:before { content: ""; width: 100px; height: 0; position: absolute; top: 0; left: 0; border-bottom: 29px solid red; border-left: 29px solid #eee; border-right: 29px solid #eee; } #octagon:after { content: ""; width: 100px; height: 0; position: absolute; bottom: 0; left: 0; border-top: 29px solid red; border-left: 29px solid #eee; border-right: 29px solid #eee; } Heart via Nicolas Gallagher #heart { position: relative; width: 100px; height: 90px; } #heart:before, #heart:after { position: absolute; content: ""; left: 50px; top: 0; width: 50px; height: 80px; background: red; border-radius: 50px 50px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; } #heart:after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; } Infinity via Nicolas Gallagher #infinity { position: relative; width: 212px; height: 100px; box-sizing: content-box; } #infinity:before, #infinity:after { content: ""; box-sizing: content-box; position: absolute; top: 0; left: 0; width: 60px; height: 60px; border: 20px solid red; border-radius: 50px 50px 0 50px; transform: rotate(-45deg); } #infinity:after { left: auto; right: 0; border-radius: 50px 50px 50px 0; transform: rotate(45deg); } Diamond Square via Joseph Silber #diamond { width: 0; height: 0; border: 50px solid transparent; border-bottom-color: red; position: relative; top: -50px; } #diamond:after { content: ''; position: absolute; left: -50px; top: 50px; width: 0; height: 0; border: 50px solid transparent; border-top-color: red; } Diamond Shield via Joseph Silber #diamond-shield { width: 0; height: 0; border: 50px solid transparent; border-bottom: 20px solid red; position: relative; top: -50px; } #diamond-shield:after { content: ''; position: absolute; left: -50px; top: 20px; width: 0; height: 0; border: 50px solid transparent; border-top: 70px solid red; } Diamond Narrow via Joseph Silber #diamond-narrow { width: 0; height: 0; border: 50px solid transparent; border-bottom: 70px solid red; position: relative; top: -50px; } #diamond-narrow:after { content: ''; position: absolute; left: -50px; top: 70px; width: 0; height: 0; border: 50px solid transparent; border-top: 70px solid red; } Cut Diamond via Alexander Futekov #cut-diamond { border-style: solid; border-color: transparent transparent red transparent; border-width: 0 25px 25px 25px; height: 0; width: 50px; box-sizing: content-box; position: relative; margin: 20px 0 50px 0; } #cut-diamond:after { content: ""; position: absolute; top: 25px; left: -25px; width: 0; height: 0; border-style: solid; border-color: red transparent transparent transparent; border-width: 70px 50px 0 50px; } Egg #egg { display: block; width: 126px; height: 180px; background-color: red; border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%; } Pac-Man #pacman { width: 0px; height: 0px; border-right: 60px solid transparent; border-top: 60px solid red; border-left: 60px solid red; border-bottom: 60px solid red; border-top-left-radius: 60px; border-top-right-radius: 60px; border-bottom-left-radius: 60px; border-bottom-right-radius: 60px; } Talk Bubble #talkbubble { width: 120px; height: 80px; background: red; position: relative; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } #talkbubble:before { content: ""; position: absolute; right: 100%; top: 26px; width: 0; height: 0; border-top: 13px solid transparent; border-right: 26px solid red; border-bottom: 13px solid transparent; } 12 Point Burst via Alan Johnson #burst-12 { background: red; width: 80px; height: 80px; position: relative; text-align: center; } #burst-12:before, #burst-12:after { content: ""; position: absolute; top: 0; left: 0; height: 80px; width: 80px; background: red; } #burst-12:before { transform: rotate(30deg); } #burst-12:after { transform: rotate(60deg); } 8 Point Burst via Alan Johnson #burst-8 { background: red; width: 80px; height: 80px; position: relative; text-align: center; transform: rotate(20deg); } #burst-8:before { content: ""; position: absolute; top: 0; left: 0; height: 80px; width: 80px; background: red; transform: rotate(135deg); } Yin Yang via Alexander Futekov #yin-yang { width: 96px; box-sizing: content-box; height: 48px; background: #eee; border-color: red; border-style: solid; border-width: 2px 2px 50px 2px; border-radius: 100%; position: relative; } #yin-yang:before { content: ""; position: absolute; top: 50%; left: 0; background: #eee; border: 18px solid red; border-radius: 100%; width: 12px; height: 12px; box-sizing: content-box; } #yin-yang:after { content: ""; position: absolute; top: 50%; left: 50%; background: red; border: 18px solid #eee; border-radius: 100%; width: 12px; height: 12px; box-sizing: content-box; } Badge Ribbon via Catalin Rosu #badge-ribbon { position: relative; background: red; height: 100px; width: 100px; border-radius: 50px; } #badge-ribbon:before, #badge-ribbon:after { content: ''; position: absolute; border-bottom: 70px solid red; border-left: 40px solid transparent; border-right: 40px solid transparent; top: 70px; left: -10px; transform: rotate(-140deg); } #badge-ribbon:after { left: auto; right: -10px; transform: rotate(140deg); } Space Invader via Vlad Zinculescu #space-invader { box-shadow: 0 0 0 1em red, 0 1em 0 1em red, -2.5em 1.5em 0 .5em red, 2.5em 1.5em 0 .5em red, -3em -3em 0 0 red, 3em -3em 0 0 red, -2em -2em 0 0 red, 2em -2em 0 0 red, -3em -1em 0 0 red, -2em -1em 0 0 red, 2em -1em 0 0 red, 3em -1em 0 0 red, -4em 0 0 0 red, -3em 0 0 0 red, 3em 0 0 0 red, 4em 0 0 0 red, -5em 1em 0 0 red, -4em 1em 0 0 red, 4em 1em 0 0 red, 5em 1em 0 0 red, -5em 2em 0 0 red, 5em 2em 0 0 red, -5em 3em 0 0 red, -3em 3em 0 0 red, 3em 3em 0 0 red, 5em 3em 0 0 red, -2em 4em 0 0 red, -1em 4em 0 0 red, 1em 4em 0 0 red, 2em 4em 0 0 red; background: red; width: 1em; height: 1em; overflow: hidden; margin: 50px 0 70px 65px; } TV Screen #tv { position: relative; width: 200px; height: 150px; margin: 20px 0; background: red; border-radius: 50% / 10%; color: white; text-align: center; text-indent: .1em; } #tv:before { content: ''; position: absolute; top: 10%; bottom: 10%; right: -5%; left: -5%; background: inherit; border-radius: 5% / 50%; } Chevron via Anthony Ticknor #chevron { position: relative; text-align: center; padding: 12px; margin-bottom: 6px; height: 60px; width: 200px; } #chevron:before { content: ''; position: absolute; top: 0; left: 0; height: 100%; width: 51%; background: red; transform: skew(0deg, 6deg); } #chevron:after { content: ''; position: absolute; top: 0; right: 0; height: 100%; width: 50%; background: red; transform: skew(0deg, -6deg); } Magnifying Glass #magnifying-glass { font-size: 10em; display: inline-block; width: 0.4em; box-sizing: content-box; height: 0.4em; border: 0.1em solid red; position: relative; border-radius: 0.35em; } #magnifying-glass:before { content: ""; display: inline-block; position: absolute; right: -0.25em; bottom: -0.1em; border-width: 0; background: red; width: 0.35em; height: 0.08em; transform: rotate(45deg); } Facebook Icon via Nathan Swartz #facebook-icon { background: red; text-indent: -999em; width: 100px; height: 110px; box-sizing: content-box; border-radius: 5px; position: relative; overflow: hidden; border: 15px solid red; border-bottom: 0; } #facebook-icon:before { content: "/20"; position: absolute; background: red; width: 40px; height: 90px; bottom: -30px; right: -37px; border: 20px solid #eee; border-radius: 25px; box-sizing: content-box; } #facebook-icon:after { content: "/20"; position: absolute; width: 55px; top: 50px; height: 20px; background: #eee; right: 5px; box-sizing: content-box; } Moon via Omid Rasouli #moon { width: 80px; height: 80px; border-radius: 50%; box-shadow: 15px 15px 0 0 red; } Flag via Zoe Rooney #flag { width: 110px; height: 56px; box-sizing: content-box; padding-top: 15px; position: relative; background: red; color: white; font-size: 11px; letter-spacing: 0.2em; text-align: center; text-transform: uppercase; } #flag:after { content: ""; position: absolute; left: 0; bottom: 0; width: 0; height: 0; border-bottom: 13px solid #eee; border-left: 55px solid transparent; border-right: 55px solid transparent; } Cone via Omid Rasouli #cone { width: 0; height: 0; border-left: 70px solid transparent; border-right: 70px solid transparent; border-top: 100px solid red; border-radius: 50%; } Cross via Kaya Basharan #cross { background: red; height: 100px; position: relative; width: 20px; } #cross:after { background: red; content: ""; height: 20px; left: -40px; position: absolute; top: 40px; width: 100px; } Base via Josh Rodgers #base { background: red; display: inline-block; height: 55px; margin-left: 20px; margin-top: 55px; position: relative; width: 100px; } #base:before { border-bottom: 35px solid red; border-left: 50px solid transparent; border-right: 50px solid transparent; content: ""; height: 0; left: 0; position: absolute; top: -35px; width: 0; } Pointer via Amsakanna Freethinker #pointer { width: 200px; height: 40px; position: relative; background: red; } #pointer:after { content: ""; position: absolute; left: 0; bottom: 0; width: 0; height: 0; border-left: 20px solid white; border-top: 20px solid transparent; border-bottom: 20px solid transparent; } #pointer:before { content: ""; position: absolute; right: -20px; bottom: 0; width: 0; height: 0; border-left: 20px solid red; border-top: 20px solid transparent; border-bottom: 20px solid transparent; } Lock via Colin Bate #lock { font-size: 8px; position: relative; width: 18em; height: 13em; border-radius: 2em; top: 10em; box-sizing: border-box; border: 3.5em solid red; border-right-width: 7.5em; border-left-width: 7.5em; margin: 0 0 6rem 0; } #lock:before { content: ""; box-sizing: border-box; position: absolute; border: 2.5em solid red; width: 14em; height: 12em; left: 50%; margin-left: -7em; top: -12em; border-top-left-radius: 7em; border-top-right-radius: 7em; } #lock:after { content: ""; box-sizing: border-box; position: absolute; border: 1em solid ted; width: 5em; height: 8em; border-radius: 2.5em; left: 50%; top: -1em; margin-left: -2.5em; }

The post The Shapes of CSS appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.