A landing page for a black-and-white photography studio. Plain HTML and a single stylesheet — no framework, no bundler, no build step. The interesting part is the styling: custom properties that change value per breakpoint, so most responsive behaviour happens without writing a second layout.
Live demo: https://tecna-developer.github.io/monovision-studio/
-
Custom properties are redefined inside
:root, not overridden per block. Spacing is declared once and the breakpoints change the variable rather than the rules that use it::root { --padding-inline-container: 13%; --section-space: 5rem; @media screen and (max-width: 48rem) { --padding-inline-container: 6%; } @media screen and (max-width: 23.4375rem) { --padding-inline-container: 0.9375rem; --section-space: 3.125rem; } }
This relies on native CSS nesting, which is why the media queries sit inside the
:rootblock instead of at the end of the file. -
Percentage gutters down to a pixel floor. The container padding stays proportional (13% → 6%) while the layout has room, then switches to a fixed
0.9375remon the narrowest screens, where a percentage would collapse to almost nothing. -
Breakpoints are expressed in
rem— 90, 70, 64, 48, 36 and 23.4375rem — so they track the user's font size rather than a device width. -
Grid is used only where the relationship is two-dimensional, and the rest of the page is flexbox. The works section uses the
gridshorthand to state rows and columns in one line —repeat(2, 1fr) 1.5fr / repeat(2, 1fr), collapsing torepeat(4, 1fr) 1.5fr / 1fron phones, where the taller last row is what gives the block its rhythm. The inspiration grid stepsrepeat(4, 1fr)→repeat(2, 1fr)→1fr. -
Inter as a variable font with
font-optical-sizing: auto, so weights and optical sizing come from one file rather than a set of static cuts. -
A two-colour palette —
--dark: #000000,--light: #f5f5f7— which is the whole point of a monovision studio, and makes the photography carry the page.
There is no build step. Open index.html in a browser, or serve the directory over HTTP:
npx servenpm install only pulls normalize.css, and even that is currently loaded from a CDN in the
markup rather than from node_modules.
index.html the whole page: hero, about, works, inspiration, customers, footer
src/css/style.css every style, ~650 lines, ordered by section
src/img/ photography
src/icon/ social and UI icons as SVG
There is no JavaScript at all — the page needs none.
Sizing mixes rem for type and spacing with percentages for gutters. Class names follow a
BEM-like block__element convention (.hero__title, .works__grid,
.about__services), and the stylesheet is ordered section by section to match the markup.
Presentational only. The navigation scrolls to anchors, and nothing on the page submits or stores anything.
main is the source of truth. It used to carry a version that rendered unstyled when opened
directly — the stylesheet <link> commented out, assets on root-absolute /src/... paths —
while a separate gh-pages branch held the working copy, so every change to the <head> had
to be made twice. gh-pages has since been merged back, and main now has the active
stylesheet link, relative asset paths and the Open Graph tags.
The demo is published from gh-pages, which also carries .nojekyll. Keep the two branches
in step, or point Pages at main and retire gh-pages — with the merge in place the branch
no longer holds anything of its own.
