.ids
Intuition Design System, IDS — a design system for building landing pages, online publications, and any digital web products that are based on narratives.
Technically, IDS is a set of CSS classes and JS components. It’s not a library, but a ready-made layout template. You don’t include IDS in your project as a dependency, you don’t extend classes, you don’t override properties. Instead, you simply copy its source code and modify it however you like. No compatibility issues and no breaking updates.
IDS is distributed under the MIT license — you can use and modify it for free, no restrictions. We also don’t accept complaints, can’t provide guidance, and there’s no support service. If you’re interested but not sure how to work with it — welcome to the course “How to Design with Code”, it will help.
Setup
Basic design system parameters are set in the css/settings.css file.
Font
IDS uses the Inter font by default, the variable web version. It’s great!
But the design system isn’t tied to a specific font — you can use any font. Just place the font files in the fonts folder and edit the
Fonts section in the css/settings.css file. Please try not to pirate fonts.
Density
Different fonts suit different layout densities. Additionally, density is an aesthetic choice — sometimes you need tight layout, sometimes airy.
IDS has a variable --ids__density that affects text line-height, as well as margins and paddings of all text elements. To adjust layout
density, first try to find the optimal value for this variable, then edit individual styles.
Responsiveness
IDS assumes there are only two types of devices: mobile and desktop. This is determined by viewport width (simplified: browser window width): less than 768 px means mobile, more means desktop.
IDS implements the Fluid Typography concept — where the font-size for the whole document (the html element) is calculated based on viewport width, and then em or
rem units are used not only for text but also for margins, paddings, border radii, and sometimes element dimensions.
This approach simplifies design debugging. First, you need to find the optimal font-size range suitable for the chosen font and desired size of “regular” text.
This range is set by the variables --desktop-font-size-min and --desktop-font-size-max. You need to find values such that when the
width changes, the text scales while preserving line breaks. Then you can check the layout at just one width, knowing that at any width the element
arrangement will be preserved.
For mobile, you need to find your own pair of values --mobile-font-size-min and --mobile-font-size-max, but the idea is exactly the same — consistent layout on
phones of different widths.
Color
Color in IDS lives in variables and is split into two layers.
The first layer is the palette, the css/tokens/palette.css file: raw color values with names like --ids__color-blue-500. The palette is
theme-independent and is never used directly anywhere except the second layer.
white
rgb(255, 255, 255)
gray-100
rgb(238, 240, 242)
gray-200
rgb(220, 221, 223)
gray-400
rgb(153, 156, 160)
gray-500
rgb(115, 120, 125)
gray-600
rgb(85, 88, 92)
gray-700
rgb(55, 58, 62)
gray-800
rgb(32, 33, 36)
gray-900
rgb(18, 18, 20)
gray-950
rgb(5, 5, 5)
blue-450
rgb(60, 130, 250)
blue-500
rgb(0, 100, 240)
green-450
rgb(40, 215, 40)
green-500
rgb(0, 200, 0)
green-600
rgb(30, 170, 60)
red-450
rgb(255, 70, 95)
red-500
rgb(253, 47, 75)
yellow-500
rgb(255, 225, 0)
The second layer is semantic colors, the css/tokens/colors.css file: naming is functional, named after what it’s used for. Each semantic color
references the palette. The dark theme is just a different set of references to the same palette: each tile is labeled with the palette color the token references
in the current theme.
text
gray-950gray-200
link
blue-500blue-450
hover
green-500green-450
mark
yellow-500
code
gray-500gray-400
text-caption
gray-600gray-400
accent
red-500red-450
surface
gray-100gray-800
background
whitegray-900
Only semantic colors are used in layout. Semi-transparent variants are not stored in variables — they are derived in place with color-mix.
Not like this
color: var(--ids__accent-50);
But like this
color: var(--ids__accent);
color: color-mix(in srgb, var(--ids__accent) 50%, transparent);
Page frame
IDS doesn’t use modular grids or columns for page space organization. It’s simpler: the page consists of “floors” that go from top to bottom one after another, each takes up the full available width and can be any height. This approach doesn’t prevent creating modular grids and complex compositions inside a floor, but the isolation of floors allows easily rearranging them and eliminates any interdependency.
Wrappers
.ids__wrapper — standard floor with large margins on desktop and minimal on mobile.
.ids__wrapper.L — floor with increased width. Different only on desktop, on mobile it matches the standard.
.ids__wrapper.XL — full-width floor with minimal margins. Different only on desktop, on mobile it matches the standard.
.ids__wrapper.XXL — full-width floor without margins, on mobile too.
For single-column text inside a standard floor, an additional wrapper is used that reduces the width and leaves extra margin on the right. This is only on desktop; on mobile, full width remains.
.ids__text-width
Vertical spacing system
In IDS, wrappers have zero margins, and most other elements have only a minimal bottom margin, to lay out elements in a continuous flow.
When noticeable spacing is needed — for example, between floors or before a heading so it doesn’t stick to the previous paragraph — special spacers are used.
ids__space.S
ids__space.M
ids__space.L
ids__space.XL
Tag styling
IDS styles some commonly used tags so you can lay out large volumes of text while keeping minimal markup. Tag styles are defined only
inside the .ids container.
Here are the tags styled inside .ids.
Headings
h1
Main page heading
h2
Second level heading
h3
Third level heading
h4
Fourth level heading
h5
Fifth level heading
h6
Sixth level heading
Sometimes you don’t visually need headings as large as h1 or h2. But according to accessibility standards, the page must have an h1, and the next level must be h2, and so on, without gaps. To resolve this contradiction, we’ve prepared special classes that reduce h1 and h2:
h1.S
Main heading, reduced
h1.XS
Main heading, reduced even more
h2.XS
Second level heading, reduced
Sometimes you want to attach a label, tag, or badge above a heading. For this, the hgroup tag is used.
hgroup
p
h1
Heading label
Main page heading
Text
p
There’s never enough information for making decisions, by definition. When there’s enough information, the right move can be “calculated,” determined with high accuracy based on data, adding two and two. If there’s enough information — there’s nothing to decide.
p.loud
A designer should be independent, versatile, multidisciplinary, and complex.
p.huge
I changed my mind.
mark
code
Used to highlight an important thought or a code fragment.
Illustration
figure figcaption
List
ul li
- No,
- no
- and no.
ol li
- Basic level
- Functional level
- Empathic level
Additional text
aside
Grid
Using the .ids__sequence class, you can quickly create a grid of identical elements, implemented via display: flex. Make
.ids__sequence the parent, and wrap each grid cell in .ids__sequence-item:
.ids__sequence
.ids__sequence-item
.ids__sequence-item
Size modifier
ids__sequence.XL
Text in cell
Text in cell
ids__sequence.L
ids__sequence.S
Gap control
.ids__sequence.XL.gap-L
.ids__sequence.XL.gap-M
.ids__sequence.XL.gap-S
Table
table — regular table
tr, th, td — standard table elements. Well, except th sticks to the top of the window.
Components
.ids__sleepy
Component for animating element appearance on scroll.
Tracks element visibility and removes the
.is-sleeping class when more than 30% of the element
is visible on screen.
The component automatically initializes for all elements with
the .ids__sleepy class on page load. It
only adds and removes the modifier class, nothing more.
Accordingly, for the animation to work, you need to
-
add the
.ids__sleepyclass to all elements that should animate when appearing on screen; -
add the
.is-sleepingmodifier class definition to these elements with styles for the inactive state; - define the transition property to animate the changing properties.
ids-footnote
ids-footnote-link and ids-footnote —
components for creating popup footnotes with automatic
numbering.
The system consists of two parts: the trigger link
(ids-footnote-link) and the container with footnote content
(ids-footnote).
Usage example:
This is simple text with a
This is the content of the first footnote. It can include any markup: paragraphs, links, lists.
And this is the second footnote. Note that the number appears automatically.
A footnote can contain multiple paragraphs. If the content is too long and doesn’t fit on the screen, a “Close” button appears, and main page scrolling is blocked.
And here is a longer paragraph to show footnotes with two-digit numbers. A good footnote doesn’t interrupt
The third footnote: reading really wasn’t interrupted.
A term is a word or phrase that needs an explanation. For example, “footnote.”
A link to the original source could go here.
A digression is a thought too good to throw away, but one that breaks the rhythm of the main text.
Details are for those who read this far.
The eighth footnote is about the circle. Single-digit numbers fit in it entirely.
A pill is a rectangle with fully rounded ends. The ninth footnote is the last one in a circle.
The tenth footnote: the number no longer fits in the circle, so the badge became a pill.
The eleventh footnote — to check that the pill doesn’t fall apart.
The twelfth footnote. You can stop counting now.
The paragraph is over, and so are the footnotes.
Markup structure:
<p>
Text with
<ids-footnote-link>footnote link</ids-footnote-link>
in the text.
</p>
<ids-footnote>
<p>Footnote content.</p>
</ids-footnote>
ids-navbar
The component forms a group of links for scroll navigation from elements wrapped in the ids-nav-item tag. Required attributes:
id— unique heading identifierlabel— link text
You can see an example of such a navbar in the top left corner of this page — the section navigation of this guide is built with it.
The menu doesn’t have to be fixed relative to the window: the component can be placed anywhere, including right in the text flow.
ids-gallery
Image gallery that opens and navigates in a modal window.
The src attribute of the img tag specifies a reduced thumbnail, and the href attribute of the a tag — the link to full size. (They can match if you don’t want to bother with thumbnails). If the full-size image is different, you need to specify its dimensions in the
data-pswp-width and data-pswp-height attributes.
The content of figcaption is displayed under the preview in the grid and in the modal window when viewing.
.ids__inline-gallery
Gallery that switches with horizontal cursor movement (and swipe gesture on mobile). Built from a sequence of static images and used when you need controlled animation. Or whatever else you can think of.
The element takes the width of the parent container. Proportions are set explicitly via the --img-aspect-ratio variable in width / height format. These are the image proportions, not the entire element — it’s easiest to write the file dimensions in pixels there.
If image proportions differ from those set in the variable, images scale to fill the container (object-fit: cover) and are centered.
You can add a link, and then the entire element becomes clickable, and images on hover will have increased brightness.
There are current position indicators — numeric and two graphical variants.
.ids__rounded
Modifier for rounding corners not with a circle segment, but with a superellipse.
The rounding radius is set in the --ids__radius variable, which means it can be set both globally, for the entire document, and locally, for a specific section or element.
ids-gen-cover
Generative cover. The image is built deterministically from two numbers in the seed-a and seed-b attributes: the same seeds always produce the same picture. Tag content becomes a caption over the image.
On hover the color window shifts one palette step. Film grain sits on top (SVG noise, mix-blend-mode: overlay); turn it off with grain="off".