Optical illusion art: geometric patterns creating visual movement and depth via contrast and repetition.
Op Art – short for Optical Art – is a style of abstract visual art that exploits the mechanics of human perception to produce illusions of movement, vibration, warping, and depth from entirely flat, static surfaces. The movement crystallized in the early 1960s, with the term itself coined by a Time magazine critic in 1964, though its roots stretch back to the color-interaction experiments of Josef Albers in the 1930s and the geometric abstractions of Victor Vasarely beginning in 1938. Vasarely, widely regarded as the father of Op Art, demonstrated with works like Zebras that precise arrangements of curvilinear black and white stripes could produce a visceral sense of three-dimensional form from flat shapes alone. The movement achieved mainstream recognition with the landmark 1965 exhibition “The Responsive Eye” at the Museum of Modern Art in New York, which showcased Bridget Riley, Richard Anuszkiewicz, Julian Stanczak, and other practitioners whose mathematically rigorous compositions confounded and delighted audiences.
At its core, Op Art is built on a deeply scientific understanding of how the eye and brain process pattern, contrast, and color adjacency. Artists exploit phenomena like simultaneous contrast (where complementary colors placed side by side appear to vibrate), Mach bands (where the eye exaggerates luminance differences at edges), and pattern-induced motion illusions (where repetitive geometric fields trick the visual cortex into perceiving movement that does not exist). The discipline demands meticulous precision – clean edges, mathematically calculated spacing, and exact color relationships. Unlike expressionistic movements, there is no room for gestural looseness; the optical effect depends on absolute geometric control.
Translating Op Art to web design means embracing its power to arrest attention, create kinetic energy without animation, and produce visual complexity from simple, repeatable elements. CSS is remarkably well-suited to Op Art’s vocabulary: repeating gradients, precise border calculations, transforms, and custom properties can reproduce the concentric circles, moire patterns, and checkerboard distortions that define the style. On screen, Op Art aesthetics work powerfully for hero sections, loading states, background textures, and accent elements. The key challenge is balance – the same intensity that captivates can also overwhelm or cause discomfort if applied without restraint. Effective Op Art web design uses optical patterns as punctuation rather than prose, pairing high-contrast illusion zones with generous whitespace and clean typographic hierarchies so that the eye has room to rest between moments of perceptual challenge.
Op Art’s palette is rooted in maximizing perceptual contrast. The movement’s earliest and most iconic works are strictly black and white, exploiting the maximum possible luminance differential. When color entered the Op Art vocabulary – pioneered by artists like Bridget Riley (from 1967), Richard Anuszkiewicz, and Julian Stanczak – it was deployed according to the principles of simultaneous contrast and chromatic vibration: complementary hues of equal intensity placed in direct adjacency to produce the most aggressive retinal stimulation. The palette below includes the essential black-white foundation alongside carefully chosen complementary pairs and high-saturation primaries that produce authentic Op Art chromatic effects.
| Swatch | Hex | Role / Usage |
|---|---|---|
#000000 |
Pure black – primary pattern element, maximum contrast anchor | |
#FFFFFF |
Pure white – counter-pattern element, backgrounds, rest zones | |
#1A1A1A |
Near-black – text, UI surfaces, softer dark alternative | |
#F0F0F0 |
Off-white – secondary backgrounds, reduced glare | |
#808080 |
Neutral gray – transitional tone, muted structural elements | |
#FF0000 |
Vibrant red – chromatic vibration pair with cyan/green | |
#00FF00 |
Vibrant green – complementary to red, maximum chromatic tension | |
#0000FF |
Pure blue – vibration pair with orange, deep contrast | |
#FF8C00 |
Vivid orange – complementary to blue, warm high-energy accent | |
#8B00FF |
Electric violet – complementary to yellow, psychedelic edge | |
#FFD700 |
Bright yellow – complementary to violet, high luminance | |
#00CED1 |
Cyan-teal – complementary to red-orange, cool contrast | |
#FF1493 |
Hot pink – Bridget Riley-inspired chromatic stripe accent | |
#39FF14 |
Neon green – extreme vibration against black or magenta | |
#333333 |
Dark charcoal – secondary text, less harsh than pure black |
:root {
/* Core black & white */
--op-black: #000000;
--op-white: #ffffff;
--op-near-black: #1a1a1a;
--op-off-white: #f0f0f0;
--op-gray: #808080;
--op-charcoal: #333333;
/* Complementary pair: Red / Green */
--op-red: #ff0000;
--op-green: #00ff00;
/* Complementary pair: Blue / Orange */
--op-blue: #0000ff;
--op-orange: #ff8c00;
/* Complementary pair: Violet / Yellow */
--op-violet: #8b00ff;
--op-yellow: #ffd700;
/* Accent colors */
--op-cyan: #00ced1;
--op-hot-pink: #ff1493;
--op-neon-green: #39ff14;
/* Semantic tokens */
--op-bg-primary: #ffffff;
--op-bg-dark: #000000;
--op-bg-soft: #f0f0f0;
--op-text-primary: #000000;
--op-text-inverse: #ffffff;
--op-text-secondary: #333333;
/* Pattern tokens */
--op-stripe-width: 4px;
--op-pattern-speed: 20s;
}
Op Art typography serves as a counterweight to the visual intensity of optical pattern fields. Type must be authoritative, geometric, and supremely legible – it anchors the viewer’s focus amid perceptual turbulence. Geometric sans-serif faces echo the mathematical precision of Op Art patterns while maintaining the clean hard edges essential to the aesthetic. Heavy weights command attention in heading roles, while lighter weights provide comfortable reading in body contexts. Avoid decorative, script, or serif faces that would clash with the rigorous geometry; type should feel like it was engineered on the same grid as the patterns themselves.
| Font | Weight(s) | Usage | Link |
|---|---|---|---|
| Space Grotesk | 400, 500, 700 | Headings, display text | Google Fonts |
| Inter | 400, 500, 700 | Body text, UI elements | Google Fonts |
| Outfit | 400, 600, 800 | Headings, labels | Google Fonts |
| Syne | 400, 700, 800 | Display, hero text | Google Fonts |
| DM Sans | 400, 500, 700 | Body, secondary text | Google Fonts |
| Jost | 400, 600, 700 | Geometric headings | Google Fonts |
| Barlow | 400, 600, 700 | Navigation, compact labels | Google Fonts |
| Archivo | 400, 700, 900 | Bold headlines, impact text | Google Fonts |
| Heading | Body | Vibe |
|---|---|---|
| Space Grotesk (700) | Inter (400) | Precise, engineered, modern |
| Syne (800) | DM Sans (400) | Bold art-world energy with clean readability |
| Outfit (800) | Inter (400) | Rounded geometry, friendly precision |
| Archivo (900) | DM Sans (400) | Maximum impact, high-contrast authority |
| Jost (700) | Barlow (400) | Bauhaus-descended geometric purity |
/* Import fonts */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Inter:wght@400;500;700&display=swap');
/* Headings */
h1, h2, h3, h4, h5, h6 {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
color: var(--op-text-primary);
line-height: 1.05;
letter-spacing: -0.02em;
text-transform: uppercase;
}
/* Display / Hero text */
.op-display {
font-family: 'Space Grotesk', sans-serif;
font-size: clamp(3rem, 8vw, 7rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 0.95;
text-transform: uppercase;
}
/* Body text */
body {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 1rem;
line-height: 1.7;
color: var(--op-text-secondary);
}
/* Labels and captions */
.op-label {
font-family: 'Space Grotesk', sans-serif;
font-weight: 500;
font-size: 0.8rem;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.op-caption {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 0.85rem;
color: var(--op-gray);
line-height: 1.5;
}
clamp() for pattern dimensions so optical effects maintain their proportion and intensity across screen sizesA card component that uses a subtle optical pattern border and clean interior, creating depth through contrast between the patterned frame and the solid content area.
.op-card {
background: var(--op-white);
border: 3px solid var(--op-black);
padding: 0;
position: relative;
overflow: hidden;
transition: transform 0.3s ease;
}
.op-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 6px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px,
var(--op-black) 3px,
var(--op-white) 3px,
var(--op-white) 6px
);
}
.op-card__body {
padding: 32px;
}
.op-card__title {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 1.25rem;
text-transform: uppercase;
margin-bottom: 0.75rem;
}
.op-card__text {
font-size: 0.95rem;
line-height: 1.6;
color: var(--op-text-secondary);
}
.op-card:hover {
transform: scale(1.02);
}
.op-card:hover::before {
background: repeating-linear-gradient(
90deg,
var(--op-red) 0px,
var(--op-red) 3px,
var(--op-white) 3px,
var(--op-white) 6px
);
}
.op-card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 32px;
}
Buttons with striped patterns that animate on hover, creating the impression that the button surface is vibrating – a micro-scale Op Art effect contained within an interactive element.
.op-button {
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--op-black);
color: var(--op-white);
border: 3px solid var(--op-black);
border-radius: 0;
padding: 14px 40px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 0.9rem;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
text-decoration: none;
position: relative;
overflow: hidden;
transition: color 0.3s ease;
}
.op-button::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
45deg,
transparent 0px,
transparent 2px,
rgba(255, 255, 255, 0.1) 2px,
rgba(255, 255, 255, 0.1) 4px
);
opacity: 0;
transition: opacity 0.3s ease;
}
.op-button:hover::before {
opacity: 1;
}
.op-button:hover {
background: var(--op-white);
color: var(--op-black);
}
/* Inverted variant for dark backgrounds */
.op-button--inverse {
background: var(--op-white);
color: var(--op-black);
border-color: var(--op-white);
}
.op-button--inverse:hover {
background: var(--op-black);
color: var(--op-white);
}
A clean, high-contrast navigation bar with an animated striped underline effect that provides visual interest without competing with the page’s optical patterns.
.op-nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
padding: 20px 40px;
background: var(--op-white);
border-bottom: 3px solid var(--op-black);
position: sticky;
top: 0;
z-index: 100;
}
.op-nav__logo {
display: flex;
align-items: center;
gap: 12px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 1.4rem;
color: var(--op-black);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.op-nav__logo-icon {
width: 28px;
height: 28px;
border-radius: 50%;
background: repeating-radial-gradient(
circle,
var(--op-black) 0px,
var(--op-black) 3px,
var(--op-white) 3px,
var(--op-white) 6px
);
border: 2px solid var(--op-black);
}
.op-nav__links {
display: flex;
gap: 32px;
list-style: none;
margin: 0;
padding: 0;
}
.op-nav__links a {
font-family: 'Space Grotesk', sans-serif;
font-weight: 500;
font-size: 0.85rem;
color: var(--op-black);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.08em;
position: relative;
transition: color 0.2s ease;
}
.op-nav__links a::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 100%;
height: 3px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px,
var(--op-black) 2px,
transparent 2px,
transparent 4px
);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.op-nav__links a:hover::after {
transform: scaleX(1);
}
A dramatic hero with a full-bleed optical pattern background and centered content overlay, creating the signature Op Art sensation that the page surface is alive with movement.
.op-hero {
position: relative;
min-height: 90vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background: var(--op-black);
}
.op-hero__pattern {
position: absolute;
inset: 0;
background:
repeating-conic-gradient(
var(--op-black) 0deg 5deg,
var(--op-white) 5deg 10deg
);
background-size: 100% 100%;
background-position: center;
opacity: 0.15;
}
.op-hero__content {
position: relative;
z-index: 2;
text-align: center;
max-width: 800px;
padding: 60px 40px;
background: rgba(0, 0, 0, 0.85);
}
.op-hero__content h1 {
font-size: clamp(3rem, 8vw, 6rem);
color: var(--op-white);
font-weight: 700;
line-height: 0.95;
margin-bottom: 1.5rem;
text-transform: uppercase;
letter-spacing: -0.02em;
}
.op-hero__content p {
font-size: 1.15rem;
color: var(--op-off-white);
max-width: 520px;
margin: 0 auto 2rem;
line-height: 1.7;
}
@media (max-width: 768px) {
.op-hero {
min-height: 70vh;
}
.op-hero__content {
padding: 40px 24px;
}
}
A pure CSS concentric ring pattern that creates the classic Op Art tunneling effect – a circle-within-circle structure that appears to recede infinitely into depth.
.op-concentric {
width: 400px;
height: 400px;
border-radius: 50%;
background: repeating-radial-gradient(
circle at center,
var(--op-black) 0px,
var(--op-black) 8px,
var(--op-white) 8px,
var(--op-white) 16px
);
margin: 0 auto;
position: relative;
}
/* Animated variant: slowly rotates for enhanced depth illusion */
.op-concentric--animated {
animation: op-pulse 4s ease-in-out infinite alternate;
}
@keyframes op-pulse {
0% {
transform: scale(1);
background-size: 100% 100%;
}
100% {
transform: scale(1.05);
background-size: 110% 110%;
}
}
/* Eccentric offset variant: off-center rings create a warp */
.op-concentric--warped {
background: repeating-radial-gradient(
circle at 40% 40%,
var(--op-black) 0px,
var(--op-black) 6px,
var(--op-white) 6px,
var(--op-white) 12px
);
}
Overlapping striped layers whose slight angular difference produces a shimmering moire effect – one of Op Art’s most mesmerizing phenomena, implemented in pure CSS.
.op-moire {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
background: var(--op-white);
}
.op-moire__layer-1,
.op-moire__layer-2 {
position: absolute;
inset: -50%;
width: 200%;
height: 200%;
}
.op-moire__layer-1 {
background: repeating-linear-gradient(
0deg,
var(--op-black) 0px,
var(--op-black) 2px,
transparent 2px,
transparent 6px
);
opacity: 0.6;
}
.op-moire__layer-2 {
background: repeating-linear-gradient(
3deg,
var(--op-black) 0px,
var(--op-black) 2px,
transparent 2px,
transparent 6px
);
opacity: 0.6;
animation: op-moire-drift 30s linear infinite;
}
@keyframes op-moire-drift {
0% { transform: rotate(0deg); }
100% { transform: rotate(6deg); }
}
Alternating complementary-color stripes that produce the retinal vibration effect Op Art is famous for – the boundary between colors appears to shimmer and buzz.
.op-vibration {
width: 100%;
height: 300px;
background: repeating-linear-gradient(
0deg,
var(--op-red) 0px,
var(--op-red) 4px,
var(--op-green) 4px,
var(--op-green) 8px
);
}
/* Blue-orange variant */
.op-vibration--warm {
background: repeating-linear-gradient(
0deg,
var(--op-blue) 0px,
var(--op-blue) 4px,
var(--op-orange) 4px,
var(--op-orange) 8px
);
}
/* Violet-yellow variant */
.op-vibration--electric {
background: repeating-linear-gradient(
0deg,
var(--op-violet) 0px,
var(--op-violet) 4px,
var(--op-yellow) 4px,
var(--op-yellow) 8px
);
}
/* Diagonal variant */
.op-vibration--diagonal {
background: repeating-linear-gradient(
45deg,
var(--op-red) 0px,
var(--op-red) 4px,
var(--op-green) 4px,
var(--op-green) 8px
);
}
/* Section divider variant: thin band */
.op-vibration-divider {
width: 100%;
height: 12px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px,
var(--op-black) 3px,
var(--op-white) 3px,
var(--op-white) 6px
);
}
A distorted checkerboard that appears to bulge outward from its center, recreating the spherical distortion effect seen in classic Op Art paintings.
.op-checkerboard {
width: 400px;
height: 400px;
margin: 0 auto;
background:
repeating-conic-gradient(
var(--op-black) 0% 25%,
var(--op-white) 0% 50%
)
50% / 40px 40px;
border-radius: 50%;
position: relative;
}
/* Creates a lens-like warp illusion via layered radial gradient */
.op-checkerboard::after {
content: '';
position: absolute;
inset: 0;
border-radius: 50%;
background: radial-gradient(
circle at center,
transparent 0%,
transparent 40%,
rgba(255, 255, 255, 0.3) 70%,
rgba(255, 255, 255, 0.8) 100%
);
}
/* Animated scale for pulsating sphere */
.op-checkerboard--pulse {
animation: op-check-pulse 3s ease-in-out infinite alternate;
}
@keyframes op-check-pulse {
0% { background-size: 40px 40px; }
100% { background-size: 32px 32px; }
}
prefers-reduced-motion| Aesthetic | Relationship |
|---|---|
| Bauhaus | Shared emphasis on geometric precision, mathematical structure, and the reduction of form to elemental shapes; Bauhaus grid discipline informs Op Art’s systematic approach |
| De Stijl | Parallel geometric abstraction movement; De Stijl’s strict horizontals, verticals, and primary colors provided a formal vocabulary that Op Art extended into perceptual illusion |
| Minimalism | Both pursue maximum effect from minimal means; Minimalism’s reductive philosophy aligns with Op Art’s use of simple elements to produce complex perceptual results |
| Kinetic Typography | Kinetic art and Op Art share the goal of creating movement from static forms; kinetic typography applies this principle to letterforms |
| Psychedelic | Psychedelic design borrowed heavily from Op Art’s vibrating patterns and chromatic intensity, adding organic forms and countercultural symbolism |
| Glitch Art | Both exploit visual disruption and perceptual confusion as aesthetic tools; Glitch Art’s digital artifacts parallel Op Art’s analog pattern interference |
| Space Age | Contemporary 1960s movement; shared the era’s fascination with science, technology, and perceptual experimentation |
| Constructivism | Precursor movement that established geometric abstraction as a serious artistic language; Op Art inherited its systematic, non-representational approach |
| Vaporwave | Vaporwave’s grid distortions and retro-digital aesthetic occasionally channel Op Art’s warped geometry through a nostalgic digital lens |
| Memphis Design | Postmodern reaction that borrowed Op Art’s bold patterns and high contrast but applied them with playful irreverence rather than mathematical rigor |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Op Art -- Optical Illusion Design</title>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<style>
/* =============================================
CSS CUSTOM PROPERTIES
============================================= */
:root {
--op-black: #000000;
--op-white: #ffffff;
--op-near-black: #1a1a1a;
--op-off-white: #f0f0f0;
--op-gray: #808080;
--op-charcoal: #333333;
--op-red: #ff0000;
--op-green: #00ff00;
--op-blue: #0000ff;
--op-orange: #ff8c00;
--op-violet: #8b00ff;
--op-yellow: #ffd700;
--op-cyan: #00ced1;
--op-hot-pink: #ff1493;
--op-neon-green: #39ff14;
}
/* =============================================
RESET & BASE
============================================= */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: var(--op-white);
color: var(--op-black);
font-family: 'Inter', sans-serif;
font-weight: 400;
line-height: 1.7;
}
h1, h2, h3, h4 {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
text-transform: uppercase;
line-height: 1.05;
letter-spacing: -0.02em;
}
a { color: inherit; }
/* =============================================
UTILITY: REDUCED MOTION
============================================= */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* =============================================
NAVIGATION
============================================= */
nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
padding: 20px 40px;
border-bottom: 3px solid var(--op-black);
background: var(--op-white);
position: sticky;
top: 0;
z-index: 100;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 1.4rem;
color: var(--op-black);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.logo-icon {
width: 28px;
height: 28px;
border-radius: 50%;
background: repeating-radial-gradient(
circle,
var(--op-black) 0px, var(--op-black) 3px,
var(--op-white) 3px, var(--op-white) 6px
);
border: 2px solid var(--op-black);
}
nav ul {
display: flex;
gap: 28px;
list-style: none;
}
nav ul a {
font-family: 'Space Grotesk', sans-serif;
font-weight: 500;
font-size: 0.85rem;
color: var(--op-black);
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.08em;
position: relative;
transition: color 0.2s;
}
nav ul a::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 100%;
height: 3px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px, var(--op-black) 2px,
transparent 2px, transparent 4px
);
transform: scaleX(0);
transition: transform 0.3s ease;
}
nav ul a:hover::after {
transform: scaleX(1);
}
/* =============================================
HERO SECTION
============================================= */
.hero {
position: relative;
min-height: 90vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--op-black);
overflow: hidden;
}
.hero-pattern {
position: absolute;
inset: 0;
background: repeating-conic-gradient(
var(--op-black) 0deg 5deg,
var(--op-white) 5deg 10deg
);
background-position: center;
opacity: 0.12;
animation: hero-rotate 60s linear infinite;
}
@keyframes hero-rotate {
0% { transform: rotate(0deg) scale(1.5); }
100% { transform: rotate(360deg) scale(1.5); }
}
.hero-content {
position: relative;
z-index: 2;
text-align: center;
max-width: 800px;
padding: 60px 48px;
background: rgba(0, 0, 0, 0.88);
border: 2px solid rgba(255, 255, 255, 0.15);
}
.hero h1 {
font-size: clamp(2.8rem, 8vw, 6rem);
color: var(--op-white);
margin-bottom: 1.25rem;
letter-spacing: -0.03em;
line-height: 0.95;
}
.hero h1 .accent {
background: linear-gradient(90deg, var(--op-red), var(--op-hot-pink));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
font-size: 1.15rem;
color: var(--op-off-white);
max-width: 500px;
margin: 0 auto 2rem;
line-height: 1.7;
}
.btn {
display: inline-block;
background: var(--op-white);
color: var(--op-black);
border: 3px solid var(--op-white);
padding: 14px 40px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.1em;
text-decoration: none;
cursor: pointer;
position: relative;
overflow: hidden;
transition: background 0.3s, color 0.3s;
}
.btn:hover {
background: transparent;
color: var(--op-white);
}
.btn--dark {
background: var(--op-black);
color: var(--op-white);
border-color: var(--op-black);
}
.btn--dark:hover {
background: transparent;
color: var(--op-black);
}
/* =============================================
STRIPE DIVIDER
============================================= */
.stripe-divider {
width: 100%;
height: 12px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px, var(--op-black) 3px,
var(--op-white) 3px, var(--op-white) 6px
);
}
.stripe-divider--color {
background: repeating-linear-gradient(
90deg,
var(--op-red) 0px, var(--op-red) 4px,
var(--op-green) 4px, var(--op-green) 8px
);
}
/* =============================================
ABOUT SECTION
============================================= */
.about {
max-width: 1200px;
margin: 0 auto;
padding: 100px 40px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 60px;
align-items: center;
}
.about h2 {
font-size: 2.5rem;
margin-bottom: 1.5rem;
}
.about p {
font-size: 1rem;
color: var(--op-charcoal);
margin-bottom: 1rem;
line-height: 1.8;
}
.concentric-ring {
width: 100%;
max-width: 380px;
aspect-ratio: 1;
border-radius: 50%;
background: repeating-radial-gradient(
circle at center,
var(--op-black) 0px, var(--op-black) 8px,
var(--op-white) 8px, var(--op-white) 16px
);
margin: 0 auto;
animation: ring-pulse 4s ease-in-out infinite alternate;
}
@keyframes ring-pulse {
0% { transform: scale(1); }
100% { transform: scale(1.04); }
}
/* =============================================
FEATURES / CARDS
============================================= */
.features {
background: var(--op-off-white);
padding: 100px 0;
border-top: 3px solid var(--op-black);
border-bottom: 3px solid var(--op-black);
}
.features-header {
max-width: 1200px;
margin: 0 auto;
padding: 0 40px 60px;
}
.features-header h2 {
font-size: 2.5rem;
}
.features-header p {
font-size: 1.05rem;
color: var(--op-charcoal);
margin-top: 0.75rem;
max-width: 600px;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 32px;
max-width: 1200px;
margin: 0 auto;
padding: 0 40px;
}
.card {
background: var(--op-white);
border: 3px solid var(--op-black);
overflow: hidden;
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
}
.card-stripe {
height: 8px;
background: repeating-linear-gradient(
90deg,
var(--op-black) 0px, var(--op-black) 4px,
var(--op-white) 4px, var(--op-white) 8px
);
}
.card:nth-child(2) .card-stripe {
background: repeating-linear-gradient(
90deg,
var(--op-red) 0px, var(--op-red) 4px,
var(--op-green) 4px, var(--op-green) 8px
);
}
.card:nth-child(3) .card-stripe {
background: repeating-linear-gradient(
90deg,
var(--op-blue) 0px, var(--op-blue) 4px,
var(--op-orange) 4px, var(--op-orange) 8px
);
}
.card-body {
padding: 32px;
}
.card-body h3 {
font-size: 1.15rem;
margin-bottom: 0.75rem;
}
.card-body p {
font-size: 0.95rem;
color: var(--op-charcoal);
line-height: 1.6;
}
/* =============================================
ILLUSION GALLERY
============================================= */
.gallery {
background: var(--op-black);
color: var(--op-white);
padding: 100px 0;
}
.gallery-header {
max-width: 1200px;
margin: 0 auto;
padding: 0 40px 60px;
text-align: center;
}
.gallery-header h2 {
font-size: 2.5rem;
margin-bottom: 0.75rem;
}
.gallery-header p {
color: var(--op-gray);
font-size: 1.05rem;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
max-width: 1200px;
margin: 0 auto;
padding: 0 40px;
}
.illusion {
aspect-ratio: 1;
border: 2px solid rgba(255, 255, 255, 0.2);
overflow: hidden;
position: relative;
}
/* Illusion 1: Concentric rings */
.illusion--rings {
border-radius: 0;
background: repeating-radial-gradient(
circle at center,
var(--op-white) 0px, var(--op-white) 6px,
var(--op-black) 6px, var(--op-black) 12px
);
}
/* Illusion 2: Checkerboard */
.illusion--checker {
background:
repeating-conic-gradient(
var(--op-white) 0% 25%,
var(--op-black) 0% 50%
)
50% / 30px 30px;
}
/* Illusion 3: Moire lines */
.illusion--moire {
background: var(--op-white);
}
.illusion--moire::before,
.illusion--moire::after {
content: '';
position: absolute;
inset: -25%;
width: 150%;
height: 150%;
}
.illusion--moire::before {
background: repeating-linear-gradient(
0deg,
var(--op-black) 0px, var(--op-black) 2px,
transparent 2px, transparent 5px
);
opacity: 0.7;
}
.illusion--moire::after {
background: repeating-linear-gradient(
4deg,
var(--op-black) 0px, var(--op-black) 2px,
transparent 2px, transparent 5px
);
opacity: 0.7;
}
/* Illusion 4: Radial sunburst */
.illusion--sunburst {
background: repeating-conic-gradient(
var(--op-white) 0deg 6deg,
var(--op-black) 6deg 12deg
);
}
/* Illusion 5: Chromatic red-green stripes */
.illusion--chromatic {
background: repeating-linear-gradient(
0deg,
var(--op-red) 0px, var(--op-red) 4px,
var(--op-green) 4px, var(--op-green) 8px
);
}
/* Illusion 6: Violet-yellow vibration */
.illusion--vibration {
background: repeating-linear-gradient(
45deg,
var(--op-violet) 0px, var(--op-violet) 4px,
var(--op-yellow) 4px, var(--op-yellow) 8px
);
}
/* =============================================
STATEMENT / CTA SECTION
============================================= */
.statement {
text-align: center;
padding: 100px 40px;
background: var(--op-white);
position: relative;
}
.statement h2 {
font-size: clamp(2rem, 5vw, 3.5rem);
margin-bottom: 1.5rem;
}
.statement p {
font-size: 1.1rem;
color: var(--op-charcoal);
max-width: 560px;
margin: 0 auto 2rem;
line-height: 1.7;
}
/* =============================================
FOOTER
============================================= */
footer {
background: var(--op-black);
color: var(--op-gray);
text-align: center;
padding: 40px;
font-size: 0.85rem;
border-top: 3px solid var(--op-charcoal);
}
footer a {
color: var(--op-white);
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
/* =============================================
RESPONSIVE
============================================= */
@media (max-width: 768px) {
nav {
padding: 16px 24px;
}
nav ul {
gap: 16px;
}
.hero {
min-height: 70vh;
}
.hero-content {
padding: 40px 24px;
}
.about {
grid-template-columns: 1fr;
padding: 60px 24px;
gap: 40px;
}
.about .concentric-ring {
max-width: 280px;
}
.features-header,
.features-grid {
padding-left: 24px;
padding-right: 24px;
}
.gallery-grid {
grid-template-columns: repeat(2, 1fr);
padding: 0 24px;
}
.gallery-header {
padding: 0 24px 40px;
}
.statement {
padding: 60px 24px;
}
}
@media (max-width: 480px) {
nav ul {
display: none;
}
.gallery-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<!-- Navigation -->
<nav>
<a href="#" class="logo">
<div class="logo-icon"></div>
Op Art
</a>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#principles">Principles</a></li>
<li><a href="#gallery">Gallery</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<!-- Hero Section -->
<section class="hero">
<div class="hero-pattern"></div>
<div class="hero-content">
<h1>See the <span class="accent">Illusion</span></h1>
<p>Geometric precision meets perceptual phenomenon.
Static patterns that move, flat surfaces that breathe,
and simple forms that confound the eye.</p>
<a href="#about" class="btn">Explore</a>
</div>
</section>
<!-- Stripe Divider -->
<div class="stripe-divider"></div>
<!-- About Section -->
<section class="about" id="about">
<div>
<h2>Perception Is the Medium</h2>
<p>Op Art exploits the mechanics of human vision to produce
illusions of movement, vibration, and depth from entirely
flat, static surfaces. Rooted in the 1960s experiments of
Bridget Riley and Victor Vasarely, it transforms mathematical
precision into perceptual poetry.</p>
<p>Every stripe width, every color adjacency, every geometric
interval is calculated to trigger specific responses in the
viewer's visual cortex. The artwork is completed not on the
canvas, but inside the eye.</p>
</div>
<div class="concentric-ring"></div>
</section>
<!-- Chromatic Divider -->
<div class="stripe-divider--color"></div>
<!-- Features Section -->
<section class="features" id="principles">
<div class="features-header">
<h2>Principles</h2>
<p>The foundations of optical art, translated to digital design.</p>
</div>
<div class="features-grid">
<div class="card">
<div class="card-stripe"></div>
<div class="card-body">
<h3>Contrast</h3>
<p>Maximum luminance and chromatic differentials drive
every optical effect. Black against white. Red against
green. The boundary is where the illusion lives.</p>
</div>
</div>
<div class="card">
<div class="card-stripe"></div>
<div class="card-body">
<h3>Repetition</h3>
<p>A single line is inert. A thousand lines at precise
intervals vibrate with apparent motion. Pattern rhythm
is the engine of Op Art's kinetic energy.</p>
</div>
</div>
<div class="card">
<div class="card-stripe"></div>
<div class="card-body">
<h3>Precision</h3>
<p>Every angle, spacing, and proportion is mathematically
determined. There is no room for approximation -- the
optical effect depends on absolute geometric control.</p>
</div>
</div>
</div>
</section>
<!-- Stripe Divider -->
<div class="stripe-divider"></div>
<!-- Illusion Gallery -->
<section class="gallery" id="gallery">
<div class="gallery-header">
<h2>Optical Gallery</h2>
<p>Six fundamental Op Art patterns rendered in pure CSS.</p>
</div>
<div class="gallery-grid">
<div class="illusion illusion--rings"></div>
<div class="illusion illusion--checker"></div>
<div class="illusion illusion--moire"></div>
<div class="illusion illusion--sunburst"></div>
<div class="illusion illusion--chromatic"></div>
<div class="illusion illusion--vibration"></div>
</div>
</section>
<!-- Statement Section -->
<section class="statement" id="contact">
<h2>The Eye Completes the Art</h2>
<p>Op Art reminds us that design is not just what we put on
the screen -- it is what happens in the space between the
screen and the mind. Perception is participation.</p>
<a href="#" class="btn btn--dark">Get Started</a>
</section>
<!-- Footer -->
<footer>
<p>Built on Op Art principles. Vasarely 1938 -- Riley 1961 -- The Responsive Eye 1965.</p>
</footer>
</body>
</html>
prefers-reduced-motion – always wrap Op Art animations in a media query check; disable rotation, pulsing, and moire drift for users who request reduced motion, as optical patterns can trigger vestibular discomfort or photosensitive seizures--op-stripe-width variable lets you tune pattern density globally, making it easy to adjust for different screen densities and user preferencesrepeating-linear-gradient and repeating-radial-gradient for pattern generation – these CSS functions are hardware-accelerated and produce crisp, resolution-independent patterns without image assets@media (-webkit-min-device-pixel-ratio: 2) to adjust stripe widths for high-DPIopacity control – rather than showing raw high-contrast patterns at full intensity (which can be overwhelming), layer them beneath content at 10-20% opacity for textured backgrounds that suggest the aesthetic without assaulting the viewertransform and opacity rather than background-position or background-size to maintain smooth 60fps performance, especially on mobile