Loading...

CSS User Interface

Optional Advanced just painted a stencil on one photo. This session is a different optional toolkit: user interface. You change how the pointer, caret, and native chrome behave on a control. You are not punching holes in a hero image, and you are not splitting an article into newspaper columns.

Direct answer

CSS user-interface properties hint at interaction. cursor chooses the mouse shape (pointer, wait, help, not-allowed…). resize lets the user drag a corner — usually on a textarea. outline with outline-offset draws a focus ring that does not steal layout space (you already met outline as a box-model ring; here it is the keyboard habit). user-select can stop accidental highlighting. caret-color tints the blinking insertion mark. appearance (and -webkit-appearance) can flatten a native checkbox or search field so you restyle it. Keep focus visible. Do not turn the whole page into an unselectable poster.

Why this is not a mask or a column

A mask decides which pixels of one box stay visible. Multi-column fragments a text stream. UI properties do neither. Layout width and height stay unless resize is in play. Filters and mask-image still belong to art. Here the job is: “Does this look clickable? Can I type? Can I grow this box? Can a keyboard user see where they are?”

Cursor — tell the truth

cursor is a promise. pointer means “this is clickable.” Use it on real buttons and links. Do not put a hand on a heading that does nothing.

Cursor map for honest controls

css
a.nav-link,
button.save {
cursor: pointer;
}

button[disabled] {
cursor: not-allowed;
}

.help-hint {
cursor: help;
}

.busy-panel {
cursor: wait;
}

default is the arrow. text is the I-beam over selectable copy. grab / grabbing fit drag handles. Custom url(...) cursors exist; keep them tiny and always list a fallback keyword. A lying cursor is worse than none: people click a slogan and nothing happens.

Resize — grow a box, not a layout

resize works on overflow-capable boxes. Everyday use is a notes field:

Resize a textarea

css
textarea.notes {
min-height: 6rem;
min-width: 16rem;
max-width: 100%;
resize: vertical;
overflow: auto;
}

Values: none, both, horizontal, vertical. Pair with overflow other than visible, or the handle may never appear. Do not sprinkle resize: both on every card: the page shell should not become a pile of drag corners. min-height / max-width keep the field from collapsing or exploding.

Outline as a focus ring

The Box Model session already taught that outline sits outside the border and does not take space. In the UI toolkit you keep that ring for keyboard focus — often with :focus-visible so mouse users are not boxed on every click:

Focus outline with offset

css
button.save:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 3px;
}

button.save:focus:not(:focus-visible) {
outline: none;
}

Never ship a global *:focus { outline: none; } unless every control has an equally visible replacement (border, shadow, or ring). outline-offset pushes the ring off the edge without growing neighbors. This is still not border (which changes size) and not a mask fade on the button label.

user-select — stop accidental highlight

Selection is a feature. Turn it down only where a double-click should not paint a blue wash — a toolbar label, a drag chip — not an article.

Limit selection on chrome, not prose

css
.toolbar-label {
user-select: none;
}

article.body {
user-select: text;
}

none blocks highlighting. text is the usual readable default. all selects the whole element on one click — handy for a short code token, noisy on a paragraph. Prefixes (-webkit-user-select) still show up in old WebKit; if you need them, pair them with the standard property. Do not disable select on legal text, prices, or error messages people must copy.

caret-color — tint the insertion mark

The caret is the blinking bar in an input. Match it to the brand without hiding it:

Caret color in a field

css
input.email,
textarea.notes {
caret-color: #0f766e;
color: #0f172a;
}

caret-color: auto follows the text color. A matching caret is polish. caret-color: transparent as decoration is a trap: people cannot see where they type. This is not color on the whole page and not a mask-image on the glyph.

appearance — restyle native widgets

Browsers paint checkboxes, search fields, and date pickers with native chrome. appearance: none (plus -webkit-appearance: none where needed) strips that skin so you can draw your own:

Reset appearance then restyle

css
input.search {
appearance: none;
-webkit-appearance: none;
border: 1px solid #94a3b8;
border-radius: 0.5rem;
padding: 0.5rem 0.75rem;
}

input[type="checkbox"].tick {
appearance: none;
-webkit-appearance: none;
width: 1.15rem;
height: 1.15rem;
border: 2px solid #334155;
border-radius: 0.25rem;
}

After none, you owe a border, a checked state, and a focus ring. An invisible checkbox is not a custom checkbox. Support varies by control type; test the real widget, not only a text input. Do not use appearance to “fix” a mask that ate a photo or to replace multi-column layout.

UI vs mask vs columns vs outline-as-box

📊 UI vs mask vs columns vs outline

Tool Job Poor fit
cursor / resize / caret-color / appearance Interaction chrome on controls Stenciling a photo; newspaper columns
user-select Limit highlight on chrome, not articles Hiding copy people must paste
outline + :focus-visible Keyboard focus ring (no layout space) Replacing border math; fading labels with a mask
mask-image Soft holes on one element’s pixels Pointer shape; growing a textarea
Multi-column (column-*) Fragment flowing text Cursors, carets, native widget skin

Optional Advanced already used columns for prose and masks for pictures. User interface is the control layer. Mixing column-count onto a settings form, or mask-image onto a submit button, does not make the form “more UI.”

What not to restyle away

Do not remove every native hint. Scrollbars, carets, and focus rings exist because people need them. Touch targets still need size (you styled buttons earlier in the course). If a control is disabled, cursor: not-allowed plus a real disabled attribute is calmer than a mask that hides the label.

UI polish is not a mask or columns

css
.ok-ui {
cursor: pointer;
outline-offset: 2px;
}

.not-a-stencil {
/* don't: mask-image on the submit label to “soften” the click */
}

.not-a-newspaper {
/* don't: column-count on a login form to look advanced */
}

If the problem is a photo edge, go back to masking. If the problem is a long article, go back to columns — or to ordinary block flow. If the problem is “this does not feel clickable,” start with cursor and a real control, not a decorative filter.

Try it yourself

  1. Put cursor: pointer on a real <button> and not-allowed on [disabled].
  2. Give a textarea resize: vertical, min-height, and overflow: auto.
  3. Add :focus-visible outline + outline-offset — tab to it with the keyboard.
  4. Set user-select: none on a toolbar chip only; leave the article selectable.
  5. Tint caret-color in an input. Do not mask the field or set column-count on it.

Common mistakes

  • cursor: pointer on text that is not a link or button
  • resize: both on layout cards and nav bars
  • Global outline: none with no :focus-visible replacement
  • user-select: none on whole pages, prices, or error copy
  • caret-color: transparent “for a clean look”
  • appearance: none then no border, no checked style, no focus ring
  • Treating a mask or multi-column as user-interface polish

Summary

  • User interface CSS hints at interaction: pointer, resize, caret, native chrome
  • cursor must tell the truth; resize belongs on fields, not the page shell
  • Keep a visible focus outline; user-select and caret-color stay light-touch
  • appearance: none only when you restyle the widget completely
  • Not a mask stencil and not newspaper columns
  • Optional Advanced continues next with 3D transforms (transforms-3d)

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
7
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top