Exploring Open Props and its Capabilities
With its intuitive approach and versatile features, Open Props empowers you to create stunning designs easily. It has the perfect balance between simplicity and power. Whether you're a seasoned developer or just starting, Open Props makes styling websites a breeze. Let's explore how Open Props can help your web development workflow.
What is Open Props
Open Props is a CSS library that packs a set of CSS variables for quickly creating consistent components using “Sub-Atomic” Styles. These web design tokens are crafted to help you get great-looking results from the start using consistent naming conventions and providing lots of possibilities out-of-the-box. At the same time, it's customizable and can be gradually adopted.
Installing open props
There are many ways to get started with open props, each with its advantages. The library can be imported from a CDN or installed using npm
. You can import all or specific parts of it, and for greater control of what's bundled or not, you can use PostCSS to include only the variables you used.
From Zero to Open Props
Let's start with the simplest way to test and use open props. I'll create a simple HTML file with some structure, and we'll start from there. Create an index.html file.
mkdir site
touch site/index.html
Edit the content of your HTML file. In this example, we’ll create a landing page containing a few parts: a hero section, a section for describing the features of a service, a section for the different pricing options available and finally a section with a call to action. We’ll start just declaring the document structure. Next we’ll add some styles and finally we’ll switch to using open props variables.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super SaaS</title>
</head>
<body>
<main>
<!-- Hero Section -->
<section class="hero">
<h1>Super Saas</h1>
<p>Experience the power of our innovative software solution.</p>
<a href="#" class="btn">Get Started</a>
</section>
<!-- Features Section -->
<section class="features">
<div class="feature">
<img src="feature1.png" alt="Feature 1">
<h2>Feature 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<div class="feature">
<img src="feature2.png" alt="Feature 2">
<h2>Feature 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<div class="feature">
<img src="feature3.png" alt="Feature 3">
<h2>Feature 3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</section>
<!-- Pricing section -->
<section class="pricing">
<h2>Pricing</h2>
<div class="pricing-plans">
<div class="pricing-plan">
<h3>Basic</h3>
<p>Perfect for individuals</p>
<p class="price">$9.99/month</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
<a href="#" class="btn">Get Started</a>
</div>
<div class="pricing-plan">
<h3>Pro</h3>
<p>Great for small businesses</p>
<p class="price">$19.99/month</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
<li>Feature 4</li>
</ul>
<a href="#" class="btn">Get Started</a>
</div>
<div class="pricing-plan">
<h3>Enterprise</h3>
<p>For large organizations</p>
<p class="price">$49.99/month</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
<li>Feature 4</li>
<li>Feature 5</li>
</ul>
<a href="#" class="btn">Get Started</a>
</div>
</div>
</section>
<!-- Call to Action Section -->
<section class="cta">
<h2>Ready to get started?</h2>
<p>Sign up now and unlock the full potential of our SaaS platform.</p>
<a href="#" class="btn">Sign Up</a>
</div>
</section>
</main>
</body>
</html>
To serve our page, we could just open the file, but I prefer to use serve, which is much more versatile. To see the contents of our file, let's serve our content.
npx serve site
This command will start serving our site on port 3000.
Our site will look something like this:
Open-props core does not contain any CSS reset. After all, it’s just a set of CSS variables. This is a good start regarding the document structure.
Adding open props via CDN
Let's add open-props
to our project. To get started, add:
<head>
<!-- simplified head content for clarity -->
<link rel="stylesheet" href="https://unpkg.com/open-props"/>
</head>
This import will make the library's props available for us to use. This is a set of CSS variables. It contains variables for fonts, colors, sizes, and many more. Here is an excerpt of the content of the imported file:
:where(html) {
--font-sans: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;
--font-serif: ui-serif,serif;
--font-mono: Dank Mono,Operator Mono,Inconsolata,Fira Mono,ui-monospace,SF Mono,Monaco,Droid Sans Mono,Source Code Pro,monospace;
--font-weight-1: 100;
--font-weight-2: 200;
--font-weight-3: 300;
--font-weight-4: 400;
--font-weight-5: 500;
--font-weight-6: 600;
--font-weight-7: 700;
--font-weight-8: 800;
--font-weight-9: 900;
--font-lineheight-00: .95;
--font-lineheight-0: 1.1;
--font-lineheight-1: 1.25;
--font-lineheight-2: 1.375;
}
The :where
pseudo-class wraps all the CSS variables declarations, giving them the least specificity. That means you can always override them with ease.
This imported file is all you need to start using open props. It will provide a sensible set of variables that give you some constraints in terms of what values you can use, a palette of colors, etc. Because this is just CSS, you can opt-out by not using the variables provided.
I like these constraints because they can help with consistency and allow me to focus on other things. At the same time, you can extend this by creating your own CSS variables or just using any value whenever you want to do something different or if the exact value you want is not there.
We should include some styles to add a visual hierarchy to our document.
Working with CSS variables
Let's create a new file to hold our styles.
touch site/styles.css
And add some styles to it. We will be setting a size hierarchy to headings, using open props font-size variables. Additionally, gaps and margins will use the size variables.
h1 {
font-size: var(--font-size-8)
}
h2 {
font-size: var(--font-size-6)
}
h3 {
font-size: var(--font-size-5)
}
.pricing-plans {
display:flex;
gap: var(--size-4);
}
.pricing-plan {
flex-grow:1;
}
section + section {
margin-block:var(--size-8);
}
We can explore these variables further using open-props’ documentation. It's simple to navigate (single page), and consistent naming makes it easy to learn them.
Trying different values sometimes involves changing the number at the end of the variable name.
For example: font-size-X, where X ranges from 0 to 8 (plus an additional 00 value). Mapped to font-sizes from 0.5rem
up to 3.5rem
.
If you find your font is too small, you can add 1 to it, until you find the right size.
Colors range from 0-12: –red-0
is the lightest one (rgb(255, 245, 245)) while –red-12 is the darkest (rgb(125, 26, 26)).
There are similar ranges for many properties like font weight, size (useful for padding and margins), line height and shadows, to name a few.
Explore and find what best fits your needs.
Now, we need to include these styles on our page.
<head>
<!-- simplified head content for clarity -->
<link rel="stylesheet" href="https://unpkg.com/open-props"/>
<link rel="stylesheet" href="/styles.css"/>
</head>
Our page looks better now.
We could keep adding more styles, but we'll take a shortcut and add some defaults with Open Props' built in normalized CSS file. Besides the core of open props (that contains the variables) there’s an optional normalization file that we can use.
Let's tweak our recently added styles.css
file a bit. Let’s remove the rules for headings. Our resulting css will now look like this.
.pricing-plans {
display:flex;
gap: var(--size-4);
}
.pricing-plan {
flex-grow:1;
}
section + section {
margin-block:var(--size-8);
}
And add a new import from open-props.
<head>
<!-- simplified head content for clarity -->
<link rel="stylesheet" href="https://unpkg.com/open-props"/>
<link rel="stylesheet" href="https://unpkg.com/open-props/normalize.min.css"/>
<link rel="stylesheet" href="/styles.css"/>
</head>
Open props provides a normalization file for our CSS, which we have included. This will establish a nice-looking baseline for our styles. Additionally, it will handle light/dark mode based on your preferences. I have dark mode set and the result already looks a lot better. Some font styles and sizes have been set, and much more.
More CSS Variables
Let's add more styles to our page to explore the variables further. I'd like to give the pricing options a card style. Open Props has a section on borders and shadows that we can use for this purpose. I would also like to add a hover effect to these cards. Also, regarding spacing, I want to add more margins and padding when appropriate.
.pricing-plans {
display:flex;
gap: var(--size-4);
}
.pricing-plan {
flex-grow:1;
display: flex;
flex-direction: column;
gap: var(--size-2);
justify-content: space-between;
border-radius: var(--radius-4);
padding:var(--size-6);
box-shadow: var(--shadow-3);
}
.pricing-plan > div {
display: flex;
flex-direction: column;
gap: var(--size-2);
}
.pricing-plan:hover{
box-shadow: var(--shadow-5);
transition: box-shadow 0.3s var(--ease-out-2);
}
@media(max-width: 768px){
.pricing-plans {
flex-direction: column;
width: 100%;
}
.pricing-plan {
width: 100%;
flex-direction: row;
flex-wrap: wrap;
}
}
section + section {
margin-block:var(--size-12);
}
.feature + .feature {
margin-block-start:var(--size-8);
}
section {
display:flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: var(--size-4) var(--size-6);
gap: var(--size-4);
}
.hero, .cta{
min-block-size: 100vh;
}
.features {
justify-content: space-between;
}
With so little CSS added and using many open props variables for sizes, borders, shadows, and easing curves, we can quickly have a better-looking site.
Optimizing when using the CDN
Open props is a pretty light package; however, using the CDN will add more CSS than you'll probably use. Importing individual parts of these props according to their utility is possible. For example, import just the gradients.
<link rel="stylesheet" href="https://unpkg.com/open-props/gradients.min.css"/>
Or even a subset of colors
<link rel="stylesheet" href="https://unpkg.com/open-props/indigo.min.css"/>
These are some options to reduce the size of your app if using the CDN.
Open Props with NPM
Open Props
is framework agnostic. I want my site to use Vite. Vite is used by many frameworks nowadays and is perfect to show you the next examples and optimizations.
cd site
npm init -y
npm i -D vite
Let's add a script to our package.json
file to start our development server.
{
"scripts": {
"dev": "vite"
}
}
Now, we can start our application on port 5173 (default) by running the following command:
npm run dev
Your application should be the same as before, but we will change how we import open props.
Stop the application and remove the open-props
and normalize
imports from index.html
. Now in your terminal install the open-props package from npm.
npm i -D open-props
Once installed, import the props and the normalization files at the beginning of your styles.css file.
@import "open-props/style";
@import "open-props/normalize";
Restart your development server, and you should see the same results.
Optimizing when using NPM
Let's analyze the size of our package.
34.4 kb seems a bit much, but note that this is uncompressed. When compressed with gzip, it's closer to 9 kb.
Similar to what we did when using the CDN, we can add individual sections of the package. For example in our CSS file we could import open-props/animations
or open-props/sizes
.
If this concerns you, don't worry; we can do much better.
JIT Props
To optimize our bundled styles, we can use a PostCSS plugin called posts-jit-props. This package will ensure that we only ship the props that we are using. Vite has support for PostCSS, so setting it up is straightforward. Let's install the plugin:
npm i -D postcss-jit-props
After the installation finishes, let's create a configuration file to include it.
touch postcss.config.js
The content of your file should look like this:
// postcss.config.js
const postcssJitProps = require('postcss-jit-props');
const OpenProps = require('open-props');
module.exports = {
plugins: [
postcssJitProps(OpenProps),
]
}
Finally, remove the open-props/style
import from styles.css
. Remember that this file contains the CSS variables we will add "just in time".
Our page should still look the same, but if we analyze the size of our styles.css
file again, we can see that it has already been reduced to 13.2kb.
If you want to know where this size is coming from, the answer is that Open Props is adding all the variables used in the normalize
file + the ones that we require in our file.
If we were to remove the normalize
import, we would end up with much smaller CSS files, and the number of props added just in time would be minimal.
Try removing commenting it out (the open-props/normalize
import) from the styles.css
file. The page will look different, but it will be useful to show how just the props used are added.
2.4kB uncompressed. That's a lot less for our example. If we take a quick look at our generated file, we can see the small list of CSS variables added from open props at the top of our file (those that we use later on the file).
Open props ships with tons of variables for:
- Colors
- Gradients
- Shadows
- Aspect Ratios
- Typography
- Easing
- Animations
- Sizes
- Borders
- Z-Index
- Media Queries
- Masks You probably won't use all of these but it's hard to tell what you'll be using from the beginning of a project. To keep things light, add what you need as you go, or let JIT handle it for you.
Conclusion
Open props has much to offer and can help speed your project by leveraging some decisions upfront and providing a sensible set of predefined CSS Variables. We've learned how to install it (or not) using different methods and showcased how simple it is to use. Give it a try!