Create visually stable, harmonious web layouts using symmetrical and asymmetrical balance, proportional harmony, and design unity — the compositional principles that make interfaces feel polished and complete.
Balance, harmony, and unity are the compositional principles that determine whether a layout feels stable, satisfying, and coherent. They operate largely below conscious awareness — users feel when a layout is unbalanced or disharmonious, even if they cannot articulate why.
For developers implementing designs, these principles explain why certain CSS decisions feel 'right' — why a symmetrical form feels stable and trustworthy, why a hero with a large image on the right feels energetic rather than unstable, and why a page with consistent spacing feels professionally designed even before users read a single word.
Symmetrical balance places equal visual weight on both sides of a central axis. It communicates stability, formality, and trustworthiness — appropriate for login forms, checkout pages, and pricing displays.
Symmetrical balance in CSS:
1/* Login form: centered, equal margins, single column — perfect symmetry */
2.login-container {
3 display: flex;
4 flex-direction: column;
5 align-items: center; /* horizontal axis symmetry */
6 justify-content: center;
7 min-height: 100vh;
8 padding: var(--space-6);
9}
10
11.login-card {
12 width: 100%;
13 max-width: 28rem; /* 448px — centered card */
14 /* Symmetrical: equal space left and right from center */
15}
16
17.login-heading {
18 text-align: center; /* horizontal axis: heading centered */
19 margin-bottom: var(--space-8);
20}
21
22/* Equal-column pricing table: symmetrical */
23.pricing-grid {
24 display: grid;
25 grid-template-columns: repeat(3, 1fr); /* equal columns = symmetry */
26 gap: var(--space-6);
27}
28
29/* Radial symmetry: centered hero with equal padding */
30.hero-centered {
31 display: flex;
32 flex-direction: column;
33 align-items: center;
34 text-align: center;
35 padding: var(--space-20) var(--space-6); /* equal vertical padding top/bottom */
36}
37
38.hero-centered > * {
39 max-width: 42rem; /* constrains content to centered reading column */
40 margin-inline: auto;
41}When to use symmetrical balance:
When to avoid symmetrical balance:
Asymmetrical balance places different visual weights on each side that still achieve overall equilibrium. A small, high-contrast element on the right can balance a large, low-contrast element on the left. This creates dynamic, engaging layouts.
Visual weight factors:
Asymmetrical balance in CSS:
1/* Hero: large text (heavy left) + image (heavy right) = asymmetric balance */
2.hero-asymmetric {
3 display: grid;
4 /* Left: 58% — text content (moderate visual weight, large area) */
5 /* Right: 42% — image (high visual weight through color/texture, smaller area) */
6 grid-template-columns: 1fr 0.72fr;
7 align-items: center;
8 gap: var(--space-16);
9 padding: var(--space-20) var(--space-10);
10}
11
12/* Feature card: icon (small, high contrast) left, text right */
13.feature-card {
14 display: flex;
15 gap: var(--space-5);
16 align-items: flex-start;
17}
18
19.feature-icon {
20 /* Small (24px) but high visual weight:
21 - Colored background (color = weight)
22 - Circular shape (isolated = weight)
23 - Surrounded by whitespace */
24 width: 3rem; /* 48px */
25 height: 3rem;
26 border-radius: 0.75rem;
27 background-color: var(--color-action-subtle);
28 color: var(--color-action);
29 display: flex;
30 align-items: center;
31 justify-content: center;
32 flex-shrink: 0;
33}
34
35.feature-content { flex: 1; } /* light text content on the right */
36
37/* The 48px colored icon on the left balances the larger
38 but lighter-weight text block on the right */Creating visual weight through isolation:
1/* Isolated stat card: maximum whitespace around it increases perceived weight */
2.featured-stat {
3 padding: var(--space-12);
4 text-align: center;
5 /* Equal padding on all sides = visual isolation */
6 /* This extra isolation compensates for smaller size
7 when this card needs to balance larger content sections */
8}
9
10/* Weight through color saturation */
11.accent-badge {
12 background-color: var(--color-action); /* full saturation = heavy */
13 color: white;
14 /* This small badge carries significant visual weight due to high contrast */
15}Unity is the principle that all elements of a page belong to the same design. Without unity, pages feel fragmented — each section looks like it was designed by a different person.
Unity is achieved through consistent application of the design system:
1/* All sections use colors from the same 3-color palette */
2/* No section introduces a new color not in the system */
3.section-hero { background: var(--color-bg-page); }
4.section-features { background: var(--color-bg-surface); }
5.section-cta { background: var(--color-bg-page); }
6/* Three backgrounds from the same token set = visual unity */1/* One typeface throughout — Inter for all text */
2body { font-family: 'Inter', system-ui, sans-serif; }
3/* No section uses a different font family */
4
5/* Same heading sizes in same positions */
6.section-heading { font-size: var(--text-3xl); } /* all section headings */
7.card-heading { font-size: var(--text-xl); } /* all card headings */
8/* Consistent scale = typography unity */1/* All sections use the same padding scale */
2.section { padding-block: var(--space-16); } /* all main sections */
3.card { padding: var(--space-5); } /* all cards */
4.form-group { margin-bottom: var(--space-5); } /* all form groups */
5/* Same spacing patterns throughout = spatial unity */1/* One border-radius size for each element type */
2.card { border-radius: var(--radius-lg); } /* all cards: 12px */
3.btn { border-radius: var(--radius-md); } /* all buttons: 8px */
4.badge { border-radius: var(--radius-full); } /* all badges: pill */
5/* Consistent shapes = visual language unity */1/* Every interactive element shares the same transition properties */
2--transition: 150ms cubic-bezier(0, 0, 0.2, 1);
3
4.btn { transition: background-color var(--transition); }
5.card { transition: box-shadow var(--transition); }
6.link { transition: color var(--transition); }
7/* Same speed and easing = interaction unity — interface feels 'of one piece' */Unity violation: section with different design language
1/* BAD: Footer section breaks unity */
2.footer {
3 font-family: Georgia, serif; /* different from Inter on all other sections */
4 border-radius: 24px; /* different from 12px cards above */
5 background-color: #1a1a2e; /* new color not in the palette */
6}
7/* Users perceive this as a different product or tacked-on section */
8
9/* GOOD: Footer uses same design language */
10.footer {
11 font-family: 'Inter', system-ui, sans-serif; /* same as everywhere */
12 background-color: var(--color-text); /* dark mode reversal of page */
13 color: var(--color-bg-page); /* inverted for contrast */
14}Proportional harmony means that element sizes feel related to each other through consistent ratios. When sizes are harmonious, the layout feels designed; when sizes are arbitrary, the layout feels random.
Harmonic size relationships in typography:
1/* Adjacent type sizes should have at least 25% difference */
2
3/* GOOD: Clear size relationships */
4.heading-section { font-size: 2.25rem; } /* 36px */
5.heading-card { font-size: 1.5rem; } /* 24px — 33% smaller */
6.body-text { font-size: 1rem; } /* 16px — 33% smaller */
7.caption { font-size: 0.875rem; } /* 14px — 12.5% smaller */
8
9/* BAD: Sizes too close to be clearly different */
10.heading-section { font-size: 1.5rem; } /* 24px */
11.heading-card { font-size: 1.25rem; } /* 20px — only 17% smaller */
12.body-text { font-size: 1.125rem; } /* 18px — only 10% smaller */
13/* These sizes look like mistakes, not hierarchy */Proportional spacing:
1/* Spacing between elements follows the 4px scale with clear ratios */
2
3/* Label → Input: 4px (1 unit) */
4/* Input → Next group: 20px (5 units) */
5/* Section → Section: 64px (16 units) */
6
7/* These ratios (1:5:16) create a proportional hierarchy of space */
8/* The 1:5 label-to-group ratio makes grouping obvious */
9/* The 5:16 group-to-section ratio makes page structure obvious */Icon sizing proportional to text:
1/* Icons should scale with their text context */
2.btn-sm .btn-icon { width: 1rem; height: 1rem; } /* 16px with 13px text */
3.btn-md .btn-icon { width: 1.25rem; height: 1.25rem; } /* 20px with 15px text */
4.btn-lg .btn-icon { width: 1.5rem; height: 1.5rem; } /* 24px with 16px text */
5
6/* Proportional: icon is approximately 1.2-1.5× the text size */
7/* This ratio is consistent across all sizes */Container width proportions:
1/* Different content widths that relate harmoniously */
2.container-full { max-width: 90rem; } /* 1440px */
3.container { max-width: 80rem; } /* 1280px — 89% of full */
4.container-narrow { max-width: 48rem; } /* 768px — 53% of main */
5.container-prose { max-width: 40rem; } /* 640px — 50% of narrow */
6
7/* These widths are related: each is approximately 50-90% of the next */
8/* Jumping from 1280px to 300px would feel abrupt and unrelated */Implementing a hero section that demonstrates asymmetrical balance (content left, image right) while maintaining complete design unity with the rest of the page.
1/* Hero section: asymmetrical balance + design unity */
2
3.hero {
4 /* Asymmetrical grid: 58% content, 42% visual */
5 display: grid;
6 grid-template-columns: 1.38fr 1fr; /* ratio 1.38:1 creates natural balance */
7 align-items: center;
8 gap: var(--space-16);
9
10 /* Unity: same container constraints as other sections */
11 max-width: 80rem;
12 margin-inline: auto;
13 padding: var(--space-20) var(--space-10);
14}
15
16/* Mobile: single column (balance achieved through stacking) */
17@media (max-width: 63.9375rem) {
18 .hero {
19 grid-template-columns: 1fr;
20 gap: var(--space-10);
21 padding: var(--space-12) var(--space-6);
22 }
23 .hero-image { order: -1; } /* image above content on mobile */
24}
25
26.hero-content {}
27
28.hero-eyebrow {
29 /* Unity: same uppercase label style as other sections */
30 font-size: var(--text-xs);
31 font-weight: 600;
32 text-transform: uppercase;
33 letter-spacing: 0.08em;
34 color: var(--color-action);
35 margin-bottom: var(--space-4);
36 display: flex;
37 align-items: center;
38 gap: var(--space-2);
39}
40
41.hero-heading {
42 /* Unity: same fluid heading as h1 declarations elsewhere */
43 font-size: var(--text-fluid-h1);
44 font-weight: 700;
45 line-height: 1.2;
46 color: var(--color-text); /* unity: same token as all headings */
47 letter-spacing: -0.025em;
48 margin: 0 0 var(--space-5);
49
50 /* text-wrap: balance prevents orphan words on last line */
51 text-wrap: balance;
52}
53
54.hero-description {
55 font-size: clamp(1rem, 1.5vw + 0.5rem, 1.25rem);
56 line-height: 1.65;
57 color: var(--color-text-muted); /* unity: same muted token as all descriptions */
58 margin: 0 0 var(--space-8);
59 max-width: 42ch; /* optimal reading length even within the 58% column */
60}
61
62.hero-actions {
63 display: flex;
64 align-items: center;
65 flex-wrap: wrap;
66 gap: var(--space-4);
67}
68
69/* Unity: same button styles as all other primary buttons */
70.btn-hero { /* extends .btn-primary — no new styles */ }
71
72/* Unity: same secondary button style as elsewhere */
73.btn-hero-secondary {
74 display: inline-flex;
75 align-items: center;
76 gap: var(--space-2);
77 font-size: 1rem;
78 font-weight: 500;
79 color: var(--color-text);
80 text-decoration: none;
81 transition: color var(--transition-base);
82}
83.btn-hero-secondary:hover { color: var(--color-action); }
84
85/* Social proof: tight below CTA (proximity unity with button group) */
86.hero-social-proof {
87 display: flex;
88 align-items: center;
89 gap: var(--space-3);
90 margin-top: var(--space-6);
91 font-size: var(--text-sm);
92 color: var(--color-text-muted);
93}
94
95.hero-avatars {
96 display: flex;
97 /* Overlapping avatars — asymmetric visual interest, balanced by star rating */
98}
99
100.hero-avatar {
101 width: 2rem;
102 height: 2rem;
103 border-radius: 50%;
104 border: 2px solid var(--color-bg-page);
105 margin-left: -0.5rem; /* overlap effect */
106 object-fit: cover;
107}
108.hero-avatar:first-child { margin-left: 0; }
109
110/* IMAGE SIDE: visual weight through color and size */
111.hero-image-wrapper {
112 position: relative;
113}
114
115.hero-image {
116 width: 100%;
117 border-radius: var(--radius-xl); /* unity: same radius token as cards */
118 display: block;
119 box-shadow: 0 20px 60px rgb(0 0 0 / 0.15); /* elevation creates weight */
120 /* High visual weight: large, colored, elevated */
121 /* Balances the lighter text block on the left */
122}
123
124/* Decorative badge on image: small high-contrast element */
125.hero-image-badge {
126 position: absolute;
127 bottom: -1rem;
128 left: -1rem;
129 background: white;
130 border-radius: var(--radius-lg);
131 padding: var(--space-3) var(--space-4);
132 box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
133 display: flex;
134 align-items: center;
135 gap: var(--space-2);
136 font-size: var(--text-sm);
137 font-weight: 600;
138}
139
140/* The badge adds visual interest to the lower-left of the image,
141 creating visual tension that the eye must resolve — keeping it engaged */The 1.38:1 column ratio (58% content, 42% image) creates asymmetric balance: the text content has larger area but lower visual density, while the image has smaller area but higher visual weight through color, elevation (box-shadow), and texture. The decorative badge at the bottom-left of the image adds a high-contrast accent that creates visual tension and holds the viewer's eye in the image quadrant. Complete design unity is maintained throughout: the same tokens (--text-fluid-h1, --color-text, --color-text-muted, --radius-xl, --transition-base) are used as in every other section — the hero feels like it belongs to the same product, not a different template grafted on.
The next lesson covers Applying Design Principles to Web Design — bringing together all the principles from this module to evaluate and improve real web interface designs using a systematic approach.
Your progress is saved in this browser, on this device only.