1. The Problem of Decorative Graphics on Retina Displays
Decorative images (icons, backgrounds) are inserted via CSS using background-image. On screens with a high pixel density (Retina), raster graphics may look blurry.
Physical vs CSS pixels
A CSS pixel is a virtual unit. One CSS pixel can correspond to 2, 3, or more physical screen pixels. The DPR (Device Pixel Ratio) factor defines this relationship.
| Situation | Result |
|---|---|
File size = background-size |
Perfect quality |
File larger than background-size |
The browser shrinks it — quality is preserved |
File smaller than background-size |
The browser stretches it — quality is lost (blur) |
2. The Brute-Force Solution — an Enlarged Image
The simplest approach is to prepare the image at 2× (or 3×) larger size and specify the desired background-size in CSS:
.icon {
background-image: url("icon@2x.png"); /* 32×32 px file */
background-size: 16px 16px; /* display as 16×16 */
background-repeat: no-repeat;
}
3. Icon Font
An icon font is a font in which icons take the place of letters. Since a font is vector-based, the icons scale without any loss of quality.
Connecting it
@font-face {
font-family: "MyIcons";
src: url("fonts/icons.woff2") format("woff2");
font-weight: normal;
font-style: normal;
}
Using it via a pseudo-element
.link::before {
content: "\e901"; /* Unicode code of the icon */
font-family: "MyIcons";
font-size: 16px;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
Advantages
- Size is changed via
font-size— with no loss of quality - Color is changed via
color(like regular text) - Ready-made icon sets (Font Awesome, Material Icons, etc.)
Drawbacks
- An icon is a character (text), not graphics — semantically incorrect
- You cannot color individual parts of an icon with different colors
- An outdated approach — SVG has all the advantages without the drawbacks
4. SVG — the Modern Solution
SVG (Scalable Vector Graphics) is a vector graphics format. It scales without loss of quality because it describes shapes with formulas rather than pixels.
Two ways to use it
| Method | How | Color change | Access from JS |
|---|---|---|---|
| External file | background-image: url("icon.svg") |
No | No |
| Inline | The <svg> tag directly in the HTML |
Yes (via fill) |
Yes |
SVG structure
<svg class="icon" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s..."/>
</svg>
<svg>— the container;viewBoxsets the coordinate system<path>— the outline of the shape; thedattribute describes the curvesfill— the fill color (an attribute or a CSS property)
Controlling the color of an inline SVG
/* Remove the fill attribute from <path> in the markup! */
.icon path {
fill: #333;
}
.link:hover .icon path {
fill: #0066cc;
}
fill is set as an attribute in the <path fill="..."> tag, the CSS fill property will not override it (just like inline styles). Remove the attribute in order to control the color from CSS.Size of an inline SVG
.icon {
width: 24px;
height: 24px;
}
5. Comparison of Approaches to Decorative Graphics
| Criterion | PNG @2x | Icon font | SVG |
|---|---|---|---|
| Quality when scaling | Limited by file size | Lossless | Lossless |
| Color change in CSS | No | Yes (color) |
Yes (fill, inline only) |
| Multi-color | Yes | No | Yes (separate <path>) |
| Semantics | Graphics | Text (semantically incorrect) | Graphics |
| Browser support | All | All | All modern |
6. Styling Forms on Mobile Devices
Mobile browsers have their own default styles for form controls — rounded corners on <input>, a non-standard appearance for <select>.
Resetting the system appearance
input, select, textarea, button {
-webkit-appearance: none;
-moz-appearance: none;
border-radius: 0;
}
appearance property without a prefix is not supported by all browsers. Always use both prefixes: -webkit-appearance and -moz-appearance.Bringing back the arrow for select
After resetting appearance, the arrow will disappear from <select>. Add it via an SVG background:
select {
background-image: url("arrow-down.svg");
background-repeat: no-repeat;
background-position: right 10px center;
background-size: 12px;
padding-right: 30px;
}
border, border-radius, background, color, font-size. Do not rely on default styles — they differ across platforms.7. Automatic Phone Number Detection on iOS
iOS Safari automatically recognizes numbers that resemble phone numbers and turns them into blue underlined links with the tel: protocol.
Why a simple style reset doesn’t work
The browser does not change your tag — it wraps the text in <a href="tel:..."> inside your element. That is why styles for the parent element won’t help.
Solution 1 — an attribute selector
a[href^="tel"] {
color: inherit;
text-decoration: none;
}
Solution 2 (better) — make it a link right away
<a href="tel:+380441234567">+38 (044) 123-45-67</a>
Style the link as you need — and it will look the same on both desktop and mobile devices.
Solution 3 — completely disabling auto-detection
<meta name="format-detection" content="telephone=no">
<a href="tel:..."> links manually.8. Attribute Selectors
| Syntax | Description | Example |
|---|---|---|
[attr="value"] |
Exact match | input[type="text"] |
[attr^="value"] |
Starts with… | a[href^="tel"] |
[attr$="value"] |
Ends with… | a[href$=".pdf"] |
[attr*="value"] |
Contains a substring | a[href*="example"] |
[attr|="value"] |
Equals value or starts with value- | [class|="button"] |
Simplifying modifier classes with [class|=”…”]
The [class|="button"] selector selects an element whose class equals button or starts with button-. This lets you write the base styles once for all variants:
/* Applies to class="button", class="button-primary", class="button-large" */
[class|="button"] {
padding: 1em 2em;
border: none;
border-radius: 4px;
}
/* A specific modifier */
.button-accent {
background-color: hotpink;
}
Instead of <div class="button button-primary">, you can write just <div class="button-primary"> — the base styles are picked up automatically.
tel:, mailto: links, etc.).9. Testing Layouts with Dynamic Content
A layout must work with any amount of content — short text, long text, a varying number of elements.
What to test
- Lots of text — does the layout break?
- Little text — do empty gaps appear?
- A varying number of columns / cards
- Absence of images
margin-top for vertical centering! When the content changes (more/less text), the alignment will break. Use align-self: center or margin: auto in flex.10. Input Types for Mobile Devices
HTML5 added new types for <input> that change the virtual keyboard on mobile devices:
| Type | Keyboard | Additional features |
|---|---|---|
type="text" |
Regular text | — |
type="search" |
Text with a “Search” button | An X to clear the field, a search button instead of Enter |
type="email" |
Latin with an @ symbol | Format check with required |
type="tel" |
Numeric with +, -, #, * | Convenient number entry |
type="number" |
Numeric | Increment/decrement arrows, the step attribute |
These types affect only the virtual keyboards. A computer’s physical keyboard will not change.
Built-in validation with required
When required is combined with a typed input, the browser checks not only that the field is filled in but also its format:
<input type="email" required>
<!-- Will check for an @ and a domain -->
<input type="tel" required>
<!-- Will check that the field is filled in -->
The downside: the appearance and text of the messages differ between browsers and cannot be customized. For consistent behavior you need validation via JavaScript.
inputmode — an alternative to type=”number”
type="number" has UX problems: the increment/decrement arrows get in the way, and an accidental scroll changes the value. A better alternative is a combination of type="text" with the inputmode attribute:
<input
type="text"
inputmode="numeric"
pattern="[0-9]*"
placeholder="Enter the code"
>
inputmode="numeric" brings up the numeric keyboard on mobile, while pattern provides validation — without unnecessary arrows or accidental changes while scrolling.
type="number" — for fields where arrows are needed (product quantity, a step). inputmode="numeric" — for codes, PINs, and card numbers, where arrows get in the way.11. The pattern Attribute for Validation
The pattern attribute lets you specify a regular expression (regex) to check the entered data:
<!-- Digits only, at least 3 characters -->
<input type="text" pattern="[0-9]{3,}" required>
<!-- International phone format -->
<input type="tel" pattern="\+[0-9]{10,13}" required>
HTML validation (required, pattern) is easily bypassed via DevTools. For reliable checking you need JavaScript on the client and a check on the server.
12. Summary Table
| Topic | Key points |
|---|---|
| Retina and DPR | CSS pixel ≠ physical pixel; DPR = physical / CSS; raster on Retina — becomes blurry |
| Icon font | Icons as font characters; scales losslessly; an outdated approach |
| SVG | Vector graphics; the best solution; inline — allows fill and JS |
| Forms on mobile | -webkit-appearance: none + explicit styles; the select arrow via an SVG background |
| Phones on iOS | Auto-detection; a[href^="tel"] for styles; best — make it <a href="tel:..."> right away |
| Attribute selectors | [attr="val"], [attr^="val"], [attr$="val"], [attr*="val"], [attr|="val"] |
| Input types | search, email, tel, number — change the mobile keyboard |
| inputmode | inputmode="numeric" — a numeric keyboard without arrows; better than type="number" for codes and PINs |
| pattern | Regex validation in HTML; bypassed via DevTools; a server-side check is needed |