By · Updated

Comparison Table CSS

Two-Column Plan Comparison With Ticks, Crosses and a Highlighted Winner

No ratings yet

Layout

Colours

Content

OneTask is free, with no sign-up, and built by one person.
If this tool saved you time, a coffee helps keep new ones coming.

How the Comparison Card Builder works

This comparison table CSS builder lays out plans or products side by side. "Which one should I pick?" is answered fastest by two columns and a list of ticks. Name the two options, type one feature per line with a value for each, choose which column to highlight and copy a real HTML table with row and column headers that screen readers can navigate.

Comparison table CSS: layout that answers the question

A comparison card is tabular data, so the generated markup is a <table> rather than a grid of divs. That is not pedantry: a table gives screen reader users column and row headers announced as they move between cells, and gives browsers a layout algorithm that keeps columns aligned no matter what the cells contain. The card wrapper adds the rounded border and clips the corners.

Rows. Type each row as Label | value A | value B. Values of yes or no become a tick or cross icon; anything else is printed as text, so you can mix "Unlimited" and "5 GB" with icons in the same table. Ticks take the accent colour and crosses are faded, so a column full of ticks reads as the better option at a glance.

Headers. The top row uses <th scope="col"> and the first cell of each body row uses <th scope="row">. With both in place a screen reader entering a cell announces something like "Pro, Custom domains, Yes", which is the whole comparison in one phrase. The <caption> holds the card title and is read first.

Highlighted column. Choose Column A or B to tint that column with a light wash of the accent and add a three-pixel accent bar above its header. The tint is the accent at roughly 8% opacity, applied with an eight-digit hex colour, so it works on any background. Highlight the option you want people to choose, not the one that wins most rows.

Zebra stripes. Alternating row backgrounds help the eye track across a wide table. On a narrow two-column card they are optional; switch them off if the border rules are enough.

Widths. The label column takes 44% and the two value columns share the rest, centred. On phones the card scrolls horizontally if it must; wrap it in an element with overflow-x: auto so the page does not.

More than two options. The generator builds two because that is the common case and it fits a card. For three or more options use the same table structure and add columns; the CSS nth-child highlight rule just needs a different index.

FAQ

Should a comparison card be a table or a grid?

A table. It is tabular data with two dimensions — features by options — and only a table gives assistive technology the row and column context for each cell. CSS grid can look identical but loses that structure. The generated markup uses <th scope="col"> and <th scope="row"> so both axes are announced.

How do I make tick and cross icons accessible?

Give each SVG role="img" and an aria-label of "Yes" or "No", as the generated icons do. Without a label a screen reader either says nothing or reads "image", and the cell is meaningless. Colour alone is not enough either — the tick and cross shapes differ so the meaning survives without colour.

Can I add a third column?

Yes. Add another <th scope="col"> to the header row and a <td> to each body row. Reduce the label column width to around 34% so three value columns fit, and update the nth-child index in the highlight rules if you want a different column tinted.

How do I make the comparison work on mobile?

Wrap the card in an element with overflow-x: auto so a table that is too wide scrolls inside the page rather than breaking the layout. Alternatively stack it: at a breakpoint set the table and rows to display: block, hide the header and use td::before { content: attr(data-label) } to label each value.

Why use eight-digit hex for the highlight tint?

Because it lets the tint derive from the accent colour without a separate colour input. #ed880014 is the accent at about 8% opacity, so changing the accent recolours the tint too. Eight-digit hex is supported in every current browser.

See also: all UI Components tools, Layout & Spacing, Shadows & Motion, Shapes & SVG, Forms & Inputs, Colour.

Related tools