Let’s Look at 50+ Interesting CSS Properties & Values

Avatar of Greg Hovanesyan
Greg Hovanesyan on (Updated on )

Can it be done with CSS? Do I need JavaScript? I know a lot of us ask these question when looking at designs and interactions. Recently I decided to dig into CSS and learn all of the properties. I spent a lot of time reading reference material, writing code, and finding new solutions to old problems with my newfound knowledge.

Through my journey, I thought I would document and showcase 50 of the most interesting properties and values I found. I created use-cases for many of them, with simplified code samples you can look at, reference, and play with. I also included a number of properties that are still experimental, but will likely be usable soon. I also included several well-known properties but with lesser-known values, so you can deepen your knowledge of them even if you’ve already heard of them. There are also some browser-specific things in here.

Let’s go!


The all property resets every other property (apart from unicode-bidi and direction) properties to their initial or inherited state. It accepts these values:

initial: changes all the properties of the element or the element’s parent their initial value
inherit: changes all the properties of the element or the element’s parent to their parent value
unset: changes all the properties of the element or the element’s parent to their parent value if they are inheritable or to their own value if not

See the Pen reset: all by Greg Hovanesyan (@gregh) on CodePen.


Angles can be valid CSS values for some properties. We often use something like transform: rotate(180deg), but “deg” isn’t the only possible unit here. You can also use grad, rad and turn as well. Our transform: rotate(180deg), for example, could be written as transform: rotate(0.5turn) as well. Say you want to rotate an element 4 times, it might be the easiest choice to write rotate(4turn).

I tested it in Chrome 54, Opera 41, Firefox 50 and Safari 10.

See the Pen angle~ by Greg Hovanesyan (@gregh) on CodePen.


This property specifies what styles are applied to the element when the animation is not playing. Imagine a @keyframe animation that fades an element out (from opacity: 1; to opacity 0;). By default, after the animation is complete, it will jump back to its initial state.

See the Pen Fading out animation by Greg Hovanesyan (@gregh) on CodePen.

By using animation-fill-mode: forwards; we can get the element to stay faded out by retaining the styles in the final keyframe:

See the Pen Fading out and keep styling by Greg Hovanesyan (@gregh) on CodePen.

It accepts the following properties:

none: (default) element gets its initial styling when the animation is not executing
forwards: animation will apply the values set by the last keyframe executed. Note, that it may not be the state of the “100%” or “to” keyframe. If you set animation-iteration-count to 1.5, the last keyframe will be the 50% keyframe. Or, if the animation-direction set to reverse, the last keyframe will be the “0%” or “from” keyframe
backwards: will apply the property values defined in the keyframe at the beginning of the animation
both: the animation will follow the rules of both forwards and backwards
initial: sets animation-fill-mode to it’s default value
inherit: element inherits animation-fill-mode value from its parent

You can see in the popular library Animate.css, the .animated class uses animation-fill-mode: both.


This property defines the number of times a @keyframe animation repeats. It can also be a non-integer value, like animation-iteration-count: 1.5, which will play one full animation cycle plus half of the cycle.

See the Pen animation-iteration-count by Greg Hovanesyan (@gregh) on CodePen.


This property specifies whether the “back” side of the element is visible when the element is rotated. It is used with 3D transforms. Accepts the following values:

visible: (default) back side of element will be visible, when rotated
hidden: back side of element is not visible
initial: sets the property to its default (visible) value
inherit: get the property value from its parent

These example will illustrate that:

See the Pen backface-visibility by Greg Hovanesyan (@gregh) on CodePen.

See the Pen backface-visibility – flipping cards by Greg Hovanesyan (@gregh) on CodePen.


This property specifies if the background-image stays fixed within the viewport when you scroll the page or scrolls along with the page.

Scroll: (default) background is fixed to the element and does not scroll with the contents
Fixed: the background stays fixed when you scroll the page (or element)
Local: scrolls along with the elements contents, if the element is scrollable

See the Pen background-attachment by Greg Hovanesyan (@gregh) on CodePen.


This property specifies how element’s background images, gradients, and colors blend with each other. For example, you could add a background-image and background-color, then set the blend-mode to “lighten”. You can also specify several blend modes, one per background.

The following blending modes can be used:

  • color
  • color-burn
  • color-dodge
  • darken
  • difference
  • exclusion
  • hard-light
  • hue
  • lighten
  • luminosity
  • multiply
  • overlay
  • saturation
  • screen
  • soft-light

See the Pen background-blend-mode by Greg Hovanesyan (@gregh) on CodePen.


The background-clip property defines the area of the element where the background is applied. You can make the background go underneath its border or fill only the area of its contents.

border-box: (default) allows background extent to the outer edge of the border
content-box: the background is clipped to the content box of the element
padding-box: the background is clipped to the outer edge of the element’s padding, so it’s applied to the content and the padding, but not underneath the border
text: the background is clipped to the foreground text.

See the Pen background-clip by Greg Hovanesyan (@gregh) on CodePen.


This property defines if the background is applied to only the element’s content area, or padding and border areas as well. The difference between this and background-clip is that background-clip crops the background, and background-origin resizes it.


This property specifies how the element’s background, padding, border, box-shadow, margin, and clip are applied when it’s wrapped onto multiple lines. If we have text wrapped on multiple lines, it would normally increase the element’s height, however, box-decoration-break can apply the styling to each line separately, instead of the whole element.

clone: every fragment of the element receives styling, box shadows and padding are applied to each fragment individually
slice: the element is rendered as if the element is not fragmented

Note: you can only use box-decoration-break on inline elements. According to MDN you can only use it on Firefox and Chrome inline elements, but I tested it and current browsers show different results. It works on Firefox and Chrome 54, Opera 41 and Safari 10 with the -webkit- prefix.

See the Pen box-decoration-break by Greg Hovanesyan (@gregh) on CodePen.


The calc() function can be used to create values. For example: width: calc(100% - 32px) will make element full width minus 32 pixels. It can be very useful for setting a column width and subtracting the margins. No need for nesting two elements and giving padding to the parent element to achieve the same result.

It accepts an expression with addition, subtraction, multiplication and division operators. Operands can be any syntax length values. You can even do something like calc(var(--someValue) / 2 - 2em)

A fallback would be like this, for browsers that don’t support it:

width: 98%; /* fallback for browsers without support for calc() */    
width: calc(100% - 1em);


The column-count property specifies the number of columns an element has. column-count: 3 will spread the elements text (or inline-* elements) into 3 columns. You can apply it to inline-block and block elements. This will not work on an element with display: table, but will work on display: table-cell.

There are a number of other column-* properties:

column-gap: property specifies the size of gap between the columns
column-rule: is a vertical line drawn between the column visually separating them. It’s a shorthand for setting this 3 properties (it is very much like border-*)
column-rule-color: specifies the color of the line. The value can be a named color (red, green, transparent), hex, rgb/rgba, hsl/hsla color values
column-rule-style: specifies the style of the line. It accepts the following values: none, hidden, dotted, dashed, solid, double, groove, ridge, inset, outset
column-rule-width: specifies the width of the line and accepts named values (thin, medium, thick), px, em, initial, inherit and unset

See the Pen columns by Greg Hovanesyan (@gregh) on CodePen.


The content property is used in conjunction with pseudo elements like ::before and ::after. Here’s one trick you can do with them. It’s a neat way to create a comma-separated <ul>.

ul > li:not(:last-child):after {
  content: ", ";


Counters let us give numbers (indexes) to elements. For example, you have an article, with several topics, each topic has an <h2> heading in the beginning, and you have <h3> subheadings. You can automatically number them!

There are four properties to work with counters:

counter-reset: resets or creates a counter. the value of this property is the name of the counter that you define
counter-increment: increments the counter. the value is of this property is the name of the counter that you want to increment
content() use :before pseudo class and content() to add the index to the elements
counter() function to retrieve the value of the counter

body {
  counter-reset: heading; /* init the counter for headings (you can give it any other name) */
h2 {
  counter-increment: heading; /* increments the counter on every <h1> tag */
  counter-reset: subheading;  /* here we init or reset the subheading */
  /* so that we get 1.1, 1.2, 1.3, then after new heading it will go 2.1, 2.2, 2.3 */
h2:before {
  content: counter(heading) " - "; /* using :before selector and counter() function we can add the index to the heading */
h3 {
  counter-increment: subheading; /* increment the subheading counter on every <h2> tag */
h3:before {
  content: counter(heading) "." counter(subheading) " - ";

See the Pen counters by Greg Hovanesyan (@gregh) on CodePen.


The currentColor keyword represents the calculated value of the elements color property.

.parent {
  color: #ccc;
  border: 1px solid currentColor;
.child {
  background: currentColor;

Another useful trick is allowing SVG icons to follow the color of button text:

button {
  color: red;
button svg {
  fill: currentColor;


The filter property applies visual effects to elements. It comes with predefined functions like blur, brightness, contrast, sepia; and you can also apply custom SVG filters.

See the Pen filters by Greg Hovanesyan (@gregh) on CodePen.

You can combine multiple filters to do complex effects. Here’s some examples where Instagram-like filters have been re-created with filters.

Here’s a trick: you can convert base color into an entirely differnet color using filters. You do it by manipulating Hue, Saturation, and Lightness. For doing so, you have to convert colors from RGB to HSL, then subtract the H, S, and L values. I’ve created a simple calculator, that generates a filter that converting base color into approximately the given target color:

See the Pen Converting colors using filters by Greg Hovanesyan (@gregh) on CodePen.


The flex property is a shorthand property as part of flexbox layout. The most common usage of it is flex: 1; which pushes an element to take up as much room as it can, or balances how much space it is using with other elements also using the flex property. The default value for flex is 0 1 auto.


The flex-flow property is a CSS shorthand for flex-direction and flex-wrap. It accepts the values of flex-direction (row, row-reverse, column, column-reverse), values of flex-wrap (nowrap, wrap, wrap-reverse). But you can also use it like flex-flow: row nowrap;


The flex-basis property defines the initial size of a flex element (a bit like width, in a horizontal flexbox layout). It accepts width values like px, em, and auto. It also accepts intrinsic sizing keywords: fill, max-content, min-content and fit-content, but those work only in Edge right now.


The font-kerning property specifies if the browser shall use kerning information stored in the font or disable it. It accepts the following values:

auto: the browser decides whether to use kerning information stored in font or not
normal: kerning is applied
none: prevent browser from using kerning information

You don’t actually use this property to manually kern type, which is about manually adjusting the spacing between individual characters. If you need to adjust the space between all letters, there is letter-spacing for that, otherwise known as tracking. If you’re interested in learning more about actually kerning type on the web, here’s some articles to explore:


The font-smoothing property controls how anti-aliasing is applied to the font. The problem is that after the standard browser anti-aliasing your font may look slightly different from what you see in design software. Here’s the situation between Webkit and Firefox:


none: turn off anti-aliasing, display fonts with sharp edges
antialiased: smooth the font on a pixel level, this make light text look lighter on dark backgrounds
subpixel-antialiased: smooth the font on a subpixel level for a better look on non-retina displays


auto: let browser choose the smoothing method
grayscale: render text with grayscale antialiasing. this gives similar output as “antialiased” on webkit, and makes light text look lighter on dark backgrounds.

See the Pen font-smoothing by Greg Hovanesyan (@gregh) on CodePen.


The value small-caps for font-variant will let us display the text in small capital letters. This can be useful when used together with the CSS ::first-line selector

See the Pen font-variant by Chris Coyier (@chriscoyier) on CodePen.


Grid layout in CSS lets us create two-dimensional grids without the problems we used to have with tables and floats. It’s a good idea to learn now as widespread support is coming soon.

A grid consists of the container and the items inside it. Then you have to specify how the space is distributed between rows and columns. The values represent column sizes and you can also give names to them.

.container {
  display: grid;
  grid-template-columns: 40px 50px auto 50px 40px;
  grid-template-rows: 25% 100px auto;

Note in the “grid-template-columns” the first and fifth columns have 40px width, the second and fourth columns 50px width, and the column in the middle will get the rest of the space. Let’s see how to position item inside the container. We have to actually set the starting and ending points to the element. The item would have the following CSS applied to it:

.item {
  grid-column-start: 2; // will start at the point where the second column starts
  grid-column-end: 5;   // will end at the point where the second column starts
  grid-row-start: 1;    // will start at the point where the first row starts
  grid-row-end: 3;      // will end at the point where the third row starts


The hyphens property specifies how the browser hyphenates the text.

none: no hyphens applied, the text will overflow the container
auto: browser will automatically hyphenate the text
manual: manually specify potential break points

There are two line break characters you can use:

&shy; – will let the browser know that it’s a place in text where the hyphenation may be performed if necessary
&amphyphen; – will render the hyphen even if the line is not broken

See the Pen hyphens by Greg Hovanesyan (@gregh) on CodePen.


The image-rendering property specifies how the image is rendered when it’s scaled. Browsers automatically apply aliasing to resized images, and you can control that with these properties:

auto: (default) the browser automatically applies aliasing
crisp-edges: the contrast and edges are preserved, so that they are not smoothed or blurred when scaled
pixelated: this value is applied only to the upsized images and makes the image appear pixelated

See the Pen image-rendering by Greg Hovanesyan (@gregh) on CodePen.


While most of the time we use list-style-type: none; on the <ul> and then apply background on the <li>, you can still consider applying list-style-image property to the <ul> element to use an image as a marker in the list.

ul {
  list-style-image: url('square.gif');


The list-style-position property specifies where shall the list marker appear. It accepts two values:

inside: markers appear inside the list item content box
outside: markers appear outside the list item content box


The object-fit property specifies how an image (<img>) element is fitted into the box established by its height and width. By default, and image will squish or stretch (if it has to) to fit the dimensions of the image box. But with this property, you can choose other options to have it scale while maintaining its proportions internally.

fill: (default) the contents of the element are size to fill the entire content box (without maintaining the aspect ration)
contain: the contents of the element are fitted inside content box maintaining the aspect ratio
cover: the contents of the element are fitted inside content box maintaining the aspect ratio, but fill the entire space
none: the contents are not resized but cropped using the given height and width
scale-down: automatically chooses between contain and none, selecting the option what would cause the smallest object size

See the Pen object-fit by Greg Hovanesyan (@gregh) on CodePen.

Without object-fit we would have had to use a parent element and absolute positioning (and other properties) to get similar results:

.element {
  width: 400px;
  height: 300px;
  position: relative;
.element img {
  position: absolute;
  height: auto;
  width: auto;
  max-height: 100%;
  max-width: 100%;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;

With object-fit: contain; it becomes much simpler:

img {
  width: 400px;
  height: 300px;
  object-fit: contain;

Be warned it doesn’t work on IE11 and Edge 14 and 15. Opera Mini supports it with the prefix -o-. On the rest of the browsers it works great without any prefixes.


This property helps you control how line breaks in text appear. It accepts a numerical value, that indicates the minimum number of lines of the block container (e.g. paragraph) that shall be left at the bottom of the page if the whole container doesn’t fit on the page or in the column.

Unfortunately it is not currently supported in Firefox.


The order property specifies the items within a flex container. the value is a number, which can be negative as well, or “inherit”, “initial”, “unset”.

<div class="flex-container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
.item:nth-child(1) { order: 3 }
.item:nth-child(2) { order: 1 }
.item:nth-child(3) { order: 2 }

This code will display the items in the 2, 3, 1 order.


This property specifies if a line break shall occur in long words if they do not fit in the container as one word.

normal: break words at normal break points
break-word: break normally unbreakable words, if there is no space

It also accepts all the normal global values: inherit, initial, unset.


There are three CSS properties that allow you adjust page breaks:

page-break-before: controls page breaks before the element
page-break-after: controls page breaks after the element
page-break-inside: controls page breaks inside of the element

These are useful when trying to control how pages print. These are the possible values for them:

auto: automatically break pages
always: always insert a page break before or after the element (even if there’s a lot of space)
avoid: avoid page break before/after/inside of the element if possible
left: insert page break so that the next page is formatted as a left page
right: insert page break so that the next page is formatted as a right page
recto: acts as right if page goes left-to-right, and left if right-to-left
verso: acts as left if page goes left-to-right, and right it right-to-left

There are several things you should know:

  1. The recto and verso values are still experimental
  2. The page-break-* property is going to be replaced by more generic break-* property in the near future
  3. Most browsers support only page-break-inside (not page-break-before or page-break-after)
  4. All browsers except Opera Mini, IE and Edge treat “left” and “right” values like “always”,
    so it’s a good idea to check if you can use it first.


Percentage values are like width: 10%. In that example, the element it is applied to would be 10% the width of the parent. But there are other properties that are based on the with the parent as well. For example, padding. If we have a container that is 400px wide 300px tall and has padding-top: 10% and padding-left: 10%, padding on both will be 40px (not 40px and 30px)!


The perspective CSS property gives an element perspective in 3D (it’s only relevant on 3D transformed elements). Its value is the distance from the viewport to the elements z plane. The value is length, that can be represented in px or em, or the “none” keyword.

The property has to be applied to the parent element (the container) or the element that you want the perspective to be applied on.

See the Pen perspective by Greg Hovanesyan (@gregh) on CodePen.


This property specifies how elements react to mouse events.

auto: the element behaves normally
none: ignores all clicks, selects, dragging, etc.

It also has special values that are unique to SVG elements:

visiblePainted: the filled and stroked part of the element are a target. The visibility has to be set to visible and stroke value to other than none.
visibleFill: only the filled part of the element is a target. The visibility has to be set to visible.
visibleStroke: only the stroked part of the element is a target. The stroke value has to be other than none.
visible: the filled and stroked part of the element are a target when the visibility of the element is set to visible.
painted: the filled and stroked part of the element are a target. The visibility of the element does not affect event processing.
fill: only the filled part of the element are a target. The visibility of the element does not affect event processing.
stroke: only the stroked part of the element are a target. The visibility of the element does not affect event processing.
all: the whole element is a target. The fill, stroke, and visibility properties of the element do not affect event processing.


You’re probably familiar with position values like static, relative, absolute, and fixed. There is another interesting value: sticky.

The elements that have position: sticky are treated as relative, until they get to the certain point, then they become fixed. Think: iPhone contacts list letter bookmarks or scroll-then-fix navigation. This is normally something we’d have to use JavaScript for, but now is doable in pure CSS.

See the Pen position: sticky by Greg Hovanesyan (@gregh) on CodePen.


The resize property defines whether the element can be resized by user. You can make an element resizeable vertically, horizontally or both.

none: element is not resizable. This is the default value for most elements, except textarea which is “both” by default
both: resizeable both directions
horizontal: resizeable horizontally
vertical: resizeable vertically

Important: in order to make an element resizeable, its overflow has to be set to something other than visible.


The shape-outside property lets us wrap text in a shape around a floated element. Maybe it’s a round image and you want text to wrap around that circle. The property will be applied to the element which you want to wrap the content around. It accepts the following values:

Keyword values: none, margin-box, padding-box, border-box, padding-box
Function values: circle(), ellipse(), inset(), polygon()

You can also pass a URL to an image around which the content will wrap, and it accepts the global initial, inherit, and unset values.

If you choose to use an image, the shape-image-threshold property will define the alpha channel threshold to separate the shape from the image. Firefox and IE still don’t have support for this property, and Safari supports it with the -webkit- prefix.

More about all this in the Almanac.

See the Pen shape-outside by Greg Hovanesyan (@gregh) on CodePen.


This CSS at-rule gives you the ability to check if the browser supports certain properties (or property/value combinations) before using them.

@supports (display: grid) {
  .container {
    display: grid;

@supports (image-rendering) {
  img {
    image-rendering: pixelated;

You can multiple properties like this:

@supports (display: grid) and ((image-rendering: crisp-edges) or (image-rendering: pixelated)) {



The var() property is part of using CSS custom properties.

CSS variables are defined by authors and represent specific values the can be used multiple times in the document. The var() function can be used as the value of any property, but cannot be used as a property or selector. The first value of the function is the name of the custom property; the second is an optional fallback value, which is used if the first argument is invalid.

Let’s take a look at the syntax:

:root {
  --primary-color: #cccccc;
body {
  color: var(--primary-color);

With a fallback value:

body {
  color: var(--primary-color, #cccccc);

In Sass, that would be just like:

$primary-color: #ccc;

body {
  color: $primary-color;

But note that custom properties and preprocessor variables aren’t quite the same.

Unfortunately, custom properties aren’t supported in IE11, Edge 14 and Opera mini. Edge 15 will have partial support.


Ever need to make all cells in a table be forced to be the same width?

table {
  table-layout: fixed;

See the Pen table-layout: fixed by Greg Hovanesyan (@gregh) on CodePen.

Here’s more information about all that.


The text-transform property can change the case of text to lowercase or uppercase. You can also capitalize the first letter of each word with capitalize.

One thing to consider: is it more-correct to use ALL CAPS type right in the HTML, or use normally cased type and use text-transform: uppercase in CSS to change it? It’s probably better to use CSS. For example, Contact us vs CONTACT US. A screen reader might read “contact U.S.” with uppercase in the HTML, instead of “Contact Us”.


The transition-timing-function property specifies the speed curve of the transition effect, like ease-in or ease-out. Here are two lesser-known known values:

steps(n, start|end): instead of specifying smooth transiting with such timing functions as ease, this completes the animation in number of steps you define. The second parameter is optional and specifies at which point within the interval shall the change occur. The default values for the second parameter is end. You can also use the shorthand functions step-start(n) and step-end(n).
cubic-bezier(n, n, n, n): your own cubic bezier function.

See the Pen transition-timing-function by Greg Hovanesyan (@gregh) on CodePen.

Use this tool to create cubic bezier timing functions.
You can also use Chrome dev tools to modify the bezier curve.

vh, vw, vmin, vmax

These values are used for sizing things relative to the viewport size. While width is alwasys relative to the parent container, vh or vw always use viewport size as a basis.

vh: 1 vh is equal to 1/100 of viewport height
vw: 1 vw is equal to 1/100 of viewport width
vmin: it is the least value of vh and vw
vmax: is the largest value of those two

For a browser window that has a viewport 1280x655px, 1vh is equal to 6.55 pixels, 1vw is equal to 12.8pixels, vmin is 6.55 pixels (smallest of the two values), and vmax is 12.8 pixels (largest of the two values).


This property defines how the white space inside the element is handled.

normal: collapse new lines, collapse spaces and tabs, text wrap
nowrap: collapse new lines, collapse spaces and tabs, text nowrap
pre: preserve new lines, preserve spaces and tabs, text nowrap
pre-wrap: preserve new lines, preserve spaces and tabs, text wrap
pre-line: preserve new lines, collapse spaces and tabs, text wrap

See the Pen dNPZpX by Greg Hovanesyan (@gregh) on CodePen.


This property specifies the line breaking rules.

normal: uses standard rules to break words
break-all: lines can be broken between any two letters
keep-all: break are prohibited between letters

See the Pen word-break by Greg Hovanesyan (@gregh) on CodePen.


The equivalent of letter-spacing, but for words! You can increase (or decrease) the amount of space between words. The standard value for this property isnormal, whiuch uses the default whitespace: 0.25em.


The will-change property lets authors tell browsers what changes to expect on an element. Changes, as in, changes to property values, likely as part of an animation. The idea is to give the browser a heads up on animations you intended to perform, as the browser can’t always predict this. When you give a hint, it can optimize for performance.

normal: perform standard optimizations
scroll-position: prepare the browser for scroll position changes
content: the contents of the element will change

You can also set specific properties that you will be changing, like this:

.will-be-animated {
  will-change: top, left;

Before the introduction of this property, we used to use tricks like this to trick the browser into animating certain elements with better performance (by “forcing” the element “onto the GPU”):

.will-be-animated {
  transform: translate3d(0, 0, 0);

This article is a good deep-dive into the subject.


The writing-mode property defines whether the text is laid out horizontally or vertically also the direction.

horizontal-tb: content flows from left to right, from top to bottom
vertical-rl: content flows from top to bottom, from right to left
vertical-lr: content flows from top to bottom, from left to right

See the Pen writing-mode by Greg Hovanesyan (@gregh) on CodePen.


This CSS pseudo-class matches input elements that have been autofilled by the browser. This gives you a chance to change that style. In Chrome, for example, they have yellow background by default.


This property lets us the the iOS momentum scrolling on elements on touch devices. There are two values:

auto: use normal scrolling, where the scrolling stops the moment when you remove your finger from screen
touch: use momentum scrolling


This property lets us hide the default callout on iOS devices. When you touch and hold the target a menu appears with information controls.

none: disables the callout
default: callout is displayed


There’s a way to hide scrollbar on an element

#container::-webkit-scrollbar {
  display: none;

There’s also a way to autohide scrollbars on IE10+ and Edge.

html {
  -ms-overflow-style: ms-autohiding-scrollbar;


Here’s full list of CSS properties that can be animated. We most often apply transitions to opacity, background-color etc, but it’s good to know that we can animate other things, like letter-spacing, for example.

See the Pen animating letter-spacing by Greg Hovanesyan (@gregh) on CodePen.