2.0 Beta

Smootify 2.0 is in public beta. Your 1.x store keeps working. Move when you want.

What changed

"CSS: states, skeletons and variables"

What Smootify's stylesheet does, the state classes and page flags you can style, the skeleton placeholders and their variables, popover backdrops, upload classes and the CSS variables Smootify writes.

v2.0 beta
Open .md1.x page ↗
On this page
  1. The stylesheet
  2. State classes
  3. loaded
  4. Page flags
  5. Skeletons
  6. Popovers and backdrops
  7. CSS variables
  8. Upload classes
  9. Snippets
  10. Where people get stuck
  11. Coming from 1.x

Smootify’s stylesheet is small and leaves your design alone. Most of what you style comes from Smootify in two forms: classes it adds to elements as their state changes, and CSS variables it writes or reads. This page lists what you can use, for combo classes in the Designer or for your own CSS.

The stylesheet

The loader adds the stylesheet when its script tag has data-css="true": see Install Smootify 2.0. It holds:

  • the condition rules: every [condition="…"], [customer-condition="…"] or [cart-condition="…"] element is hidden with display: none !important while its state does not match. Without the stylesheet, these elements always show;
  • the skeleton placeholders for elements with a skeleton attribute (below);
  • a few defaults: closed popovers are hidden, popovers and the cart’s dialog lose the browser’s padding and border (your classes still set theirs), and the cart’s dialog, the market suggestion and the store-availability dialog get a backdrop.

Your own CSS goes in a <style> tag in Site settings, Custom code, or in a Code Embed. In the Designer, the same classes work as combo classes.

State classes

Smootify adds and removes classes as things change. The main ones:

  • On smootify-product: loaded, is-available / is-not-available, is-on-sale, is-free, is-new, is-variable, price-varies, has-subscription, not-existing-variant, is-currently-out-of-stock, and the stock levels many-in-stock, low-stock, low-not-last-stock, last-in-stock.
  • On the values of a picker: is-active on the selected value, is-disabled on a value that cannot be bought (it stays clickable).
  • On smootify-cart: loaded, is-rendered, is-empty-cart, has-taxes, has-empty-quote.
  • On a product that Shopify does not return: Webflow’s w-dyn-bind-empty, on the Collection item or on smootify-product.
smootify-product.is-on-sale .product-price {
  color: #b42318;
}
variant-swatches button.is-active {
  outline: 2px solid currentColor;
}
variant-swatches button.is-disabled {
  opacity: 0.4;
}

Every element’s classes are in the Reference: state classes.

loaded

loaded goes on an element once Smootify has written it: products, prices, the cart, the account lists, sort and filter widgets, images and more. Use it for an entrance transition:

smootify-product .product-info {
  opacity: 0;
  transition: opacity 0.3s;
}
smootify-product.loaded .product-info {
  opacity: 1;
}

Page flags

Some states apply to the whole page, on html or body:

  • html[logged-in] and body.is-user-logged-in while a customer is logged in;
  • html[customer-status="loaded"] and body.customer-status-loaded once the session is known, logged in or not;
  • body.has-customer-names, has-addresses / no-addresses, has-orders / no-orders, has-subscriptions / no-subscriptions for the account pages;
  • body.has-wishlist, body.has-last-viewed, body.has-cart-upsells while those lists have products;
  • has-related, has-complementary, has-best-seller and the other has-<source> classes on html and body, while a smootify-product list with that data-id has products;
  • body.cookie-banner-visible while the smootify-consent banner shows.
html:not([logged-in]) .account-menu {
  display: none;
}

Skeletons

An element with a skeleton attribute is a placeholder until Smootify writes it. Smootify then removes the attribute, also when the value is missing and the element is hidden. Only elements with the attribute are placeholders.

  • skeleton="text", "button" or "block": a pulsing background, transparent text and border, children invisible, not clickable;
  • skeleton="image", on an Image: a pulsing blur;
  • skeleton="hide": hidden (visibility: hidden), so it keeps its space.

Their colours and corner radius come from three CSS variables.

Customer values ([customer], [customer-condition], [company] and the customer metafields) pulse the same way until html[customer-status="loaded"], without a skeleton attribute. How designers add skeletons is in loading.

Popovers and backdrops

The mini cart’s dialog, the market suggestion and the store-availability dialog get a backdrop, coloured by two CSS variables. The market suggestion and the store-availability dialog also blur the page behind, through the class with-blur, unless the element has disable-blur. Other popovers, Webflow’s Popover element included, have no backdrop: set --smootify-backdrop-color on a panel’s class to give it one. The popovers inside that panel do not get it.

A closed popover is hidden with display: var(--smootify-closed-display, none) !important, so style its open state with :popover-open. To show a closed popover in the page at some breakpoints, set --smootify-closed-display on its class there. More in Popovers and Market suggestion.

CSS variables

Five variables change the look of skeletons and backdrops. Smootify writes the other four, for your CSS to read:

--skeleton-loading-start

The first color of the pulse

Default
hsl(200, 20%, 80%)
--skeleton-loading-end

The second color of the pulse

Default
hsl(200, 20%, 95%)
--skeleton-radius

The corner radius of the placeholder

Default
4px
--smootify-backdrop-color

The backdrop of a popover, set on the panel's class, and of the mini cart's dialog

Default
none on popovers; rgba(0, 0, 0, 0.8) on the mini cart's dialog
Not passed
to popovers inside the panel
--smootify-closed-display

A closed popover shown in the page, on the panel's class at the breakpoints you choose

Default
none: a closed popover is hidden
Example
flex on desktop: a filter drawer becomes a column
--backdrop-color

The backdrop of the market suggestion and of the store-availability dialog

Default
rgba(0, 0, 0, 0.1)
--metafield-rating

A rating's share of its scale

Written on
A rating or list.rating metafield element.
Value
A percentage, such as 90%.
--metafield-color

The color of a color metafield

Written on
A color metafield element.
Value
The color.
--upload-progress

How much of a file has uploaded

Written on
Each upload item and its progress element.
Value
From 0 to 1 while the file uploads.
--scrollbar-width

The width of the page's scrollbar

Written on
html.
Value
The width, measured at load.

A property="--my-name" attribute on a metafield element writes the rating or the colour into that variable instead. See Metafields on the page.

A fill inside a rating element with width: var(--metafield-rating) draws stars, and an upload’s progress element can scale with --upload-progress:

:root {
  --skeleton-loading-start: #e4e4e7;
  --skeleton-loading-end: #f4f4f5;
  --skeleton-radius: 8px;
}
.filter-panel {
  --smootify-backdrop-color: rgba(15, 23, 42, 0.6);
}
.stars-fill {
  width: var(--metafield-rating);
}
[upload="progress"] {
  transform: scaleX(var(--upload-progress, 0));
  transform-origin: left;
}

Upload classes

Upload fields (file-uploader, file-input, configurator-file-input, server plan) use your markup and add classes you style:

  • on the element: is-dragover while a file is dragged over, is-uploading, has-files, is-full when no more files fit, is-invalid when a file was refused;
  • on each item: is-uploading, is-done, is-error, is-image.

The parts are in upload and File uploads.

Snippets

Short rules for things the Designer cannot do alone. Paste them in Site settings › Custom code › Head code, inside a <style> tag, and change the styles to fit your design.

A tooltip on swatch buttons. Buttons that show only a colour or an image can show the value’s name on hover: every variant-swatches button carries its value in data-value.

variant-swatches button { position: relative; }
variant-swatches button:hover::before {
  content: attr(data-value);
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  padding: 0.2rem 0.5rem;
  border-radius: 0.3rem;
  background: black;
  color: white;
  font-size: 0.8rem;
  white-space: nowrap;
}

No shimmer on a cart line that changes. While its quantity changes or it is removed, a line gets the class loading and a pulsing layer over it. To keep the line still (it still ignores clicks until the change is done):

cart-item.loading::before,
cart-item.loading bundle-item > *::before { display: none !important; }

A checked Radio button or Checkbox. Webflow styles the checked state of the input only. To style the whole Radio button or Checkbox, label included, when it is checked (.w--redirected-checked is the class Webflow gives a custom-styled input):

.w-radio:has(.w--redirected-checked), .w-radio:has(input:checked) { /* your styles */ }
.w-checkbox:has(.w--redirected-checked), .w-checkbox:has(input:checked) { /* your styles */ }

The page while the Navbar menu is open. Webflow styles the open state of the menu only. To change the page, for example to stop it from scrolling:

body:has([data-nav-menu-open]) { overflow: hidden; }

Where people get stuck

Check these first

  • Elements with a condition always show. The stylesheet is not loaded: add data-css="true" to the loader, or link the stylesheet.
  • Nothing pulses while the page loads. In 2.0 only elements with a skeleton attribute are placeholders. Add it where you want one.
  • Upload styles stopped working. 1.x used FilePond and its .filepond--* classes. 2.0 uses your markup: style the upload parts and classes above.
  • Styles for the cookie banner no longer apply. They target is-shopify-cookie-banner-visible, the 1.x class. In 2.0 the body class is cookie-banner-visible.

Coming from 1.x

  • No automatic skeleton. 1.x animated every text, image, button and link of an element that had not loaded yet. 2.0 animates only elements with a skeleton attribute. Adding the loaded class to switch the skeleton off is no longer needed.
  • Search, search and discovery, account lists and store availability no longer pulse on their own either: add skeleton to the placeholders you want.
  • The state classes and the condition rules are unchanged. smootify-variant now gets is-on-sale only when the compare-at price is above the price, as smootify-product does.
  • is-shopify-cookie-banner-visible is now cookie-banner-visible. .filepond--* is gone with FilePond.

    ↑ ↓ to moveEnter to openEsc to close