← The library

Corvella

One-page site for a fish and seafood restaurant

Full template Members only Open the demo
Preview of the Corvella template: a deep-sea blue screen, the “Corvella Restaurant” logo centred beneath a line-drawn shell, a plate of grilled prawns entering from the top left corner and a plate of clams from the right, and a white chevron cut into the photo of the dining room at the bottom.

What it is

A one-page marketing site for a seaside restaurant: a hero screen with the logo centred between two cut-out plates, a full-width photograph with a chevron cut into it, three rotating dishes, a wine banner, a carousel of three photos, a single sentence on blue, a booking form and a four-column footer. One page, one HTML file.

What makes this site is the blue and what gets cut into it. The large photos aren't laid edge to edge: a triangle of the background colour bites into their top or bottom edge, and it's a single line of clip-path that draws it — not an image, not a mask. The second gesture is the magnifier in the blue section: a 200 px disc following the cursor while the photograph it reveals stays put.

The design comes from a Webflow restaurant template of which only the structure has been kept. Everything else has been rewritten: jQuery, the 1.17 MB bundle holding the IX2 animation engine, the 70 kB of minified CSS, the home-made slider, a Lottie animation, the editor's badge, the Google Maps widget, and the style="opacity:0" set inline on every animated block — which a strict security policy blocks, leaving a blank page.

The site has been renamed, and nothing of the original is left in the files: name, logo, address, phone number, email, social account, dish names. The eight photographs were generated for this template and the six drawings — the logo's shell, the fish, the net, the nautilus, the scatter of shells, the neighbourhood map — are written by hand in SVG.

What you change first

The colours — five lines

Right at the top of assets/css/style.css:

--blue:       #0b3a5b;  /* blue backgrounds, text on the cream */
--blue-dark:  #06283e;  /* the same blue, one notch darker (hover) */
--blue-light: #6e9dbb;  /* the same blue, lightened: drawings laid ON the blue */
--cream:      #f1f5f7;  /* page background */
--white:      #ffffff;  /* cards and rails */

One thing to know before touching it: there are three blues, and they aren't interchangeable. The solid one holds at 10.8:1 on the cream and carries white at 11.9:1; the dark one is there for hovers (13.9:1 on the cream); the lightened one is for the nautilus, the shells and the rules laid over the blue, where the solid one would disappear (4.1:1). Changing one means changing all three — and the drawings' colour is written in the stroke attribute of the SVG files, not in the CSS.

The name

Search for “Corvella” in index.html: the title, the description, the logo repeated three times, the email address, the social account, the footer. No CSS class carries the brand name, so a find-and-replace can't break anything. The logo isn't an image: it's a paragraph with a shell in SVG and two lines of text, sized by a single variable, --mark.

The dishes

A dish is one <a class="dish">: a cut-out plate in a circle, a label beneath. Duplicate it or delete it, the grid recomposes itself. The plates are WebP files with a transparent background — if you replace the photo, cut it into a disc, otherwise the file's white corner will show against the blue.

The sizes

The type scale is declared once at the top, then redeclared at each of the four breakpoints. So a heading never gets its own media query: you change --size-h2 and every heading follows. The layout too fits into four variables, all in viewport units: --gutter, --inset, --rail et --plate.

The eleven effects, and how they're built

The settings aren't eyeballed: they're read out of the store ixData of Webflow's animation engine, then filtered down to the home page and deduplicated. The template declares 31 events there for 12 distinct effects. Eleven are reproduced; the twelfth animated the template author's business card, removed along with it.

EffectOriginalHere
Loading screenlogo y 100% → 0 and blur 10 → 0 px in 700 ms, scrim raised by −100 vh in 1 s (700 ms delay), page fading in over 500 msthree @keyframes chained by their delays, behind the class js
Hero entranceplates x −40% and +50% → 0 (1 s and 1.4 s), rotation 180° → 0, logo scale 0.5 → 1, 2.5 s delaysame durations, delay brought down to 1.5 s
Reveal from below (5 blocks)opacity + y 100 px, 1 s, outQuart, 0% threshold[data-reveal] + IntersectionObserver, threshold moved to 15%
Photo parallaxy −20% → +20% and scale 1.1 → 1 over the scrollthe script writes --p (0 → 1), le transform is worked out in CSS
Drawing parallaxfish y −60% → +30%, net 0% → +20%same --p, two amplitudes
Magnifier following the pointermask moved by ±50 vw and ±50 vh, photo moved by as much the other way--x / --y on the block, the photo carries the opposite translation
Plate hover (3 dishes)rotation 0 → 90° in 2 s, disc scale 1 → 1.1 in 500 ms; return 300 mstwo CSS transitions, same durations
Arrow link hover (3 links)label skewX −10° and x +5 px, arrow x +5 px, 300 ms; return 200 msCSS transitions, same durations
Full-screen menupanel x −100% → 0 in 400 ms, links fading in over 400 ms; closing 400 ms<details> native + @keyframes, replayed by the script
Carouselhome-made slider, 500 ms, endless loop, auto-play disabledtrack scroll-snap, two arrows, three anchors, position announced
The “Scroll” wheela 98-frame Lottie animation at 60 fpsa drawn SVG + one @keyframes of 1.6 s

What you should know

  • No external requests. 21 requests on load, all of them local. Self-hosted fonts, local images, zero CDN. Checked by listing the requests on load, not assumed. The original pulled jQuery, a Webflow bundle and Google Fonts from four domains.
  • Without JavaScript, nothing is hidden. The hidden state of the scroll reveal is written under html.js, a class set before the first paint. Checked by removing the <script>: 9 headings out of 9 visible, no block hidden, the loading screen doesn't appear and the menu still opens.
  • The loading screen doesn't depend on the script to leave. Each step is a CSS animation with a delay, not a class added by the JavaScript. If main.js fails after enhance.js has set the class, the page still finishes appearing — which is exactly the case a full-screen scrim makes dangerous.
  • The menu is a <details>. It opens by click and by keyboard, script or no script, and <summary> exposes the expanded state on its own. The script only adds the entrance animation — and it has to add it, because a closed <details> is hidden by content-visibility and a @keyframes would never replay after the first opening.
  • The carousel slides on its own. The track is a scroll container with scroll-snap: mouse, finger and arrow keys all work without a line of JavaScript, and the three dots are real anchors. The two arrows and the position announced through role="status" are the layer on top. Measured at all three widths: the last photo is reachable.
  • Zero inline styles, zero inline scripts. The template honours the site's strict security policy, checked by serving the folder with the real header: zero violations, zero JavaScript errors.
  • The trigger sits 15% up from the bottom of the screen, measured against the screen and not against the element as in the original. A threshold expressed as a fraction of the element never fires for a block taller than the viewport — and here a block visibly enters instead of having finished before it was seen.
  • The menu links are in outlined text. -webkit-text-stroke doesn't exist everywhere; where it's missing the links would be invisible, so an @supports not fills them in white.
  • Responsive checked at 390, 1440 and 2560 px, on load and throughout the scroll, with no horizontal overflow.

What isn't perfect

Better said here than left for you to find out.

  • The bottle's label is blank. The original showed a real wine brand. Writing “Corvella” on it would have meant recomposing the photo; a cream label with no text is more honest and commits nobody.
  • The map is a drawing, not a map. The original embedded a Google Maps widget: outside its host it loads nothing, and it would make an external request. map.svg is a neighbourhood plan drawn by hand; the marker moves by changing one transform.
  • The booking form has no server. It validates, then shows a confirmation and repeats the phone number. Four lines to delete in main.js and one action to fill in to wire it up.
  • The layout is in viewport units (vw), as in the original — that's what makes it hold at every width without a media query. But vw includes the scrollbar: on a browser that reserves it, expect about fifteen pixels of difference from the measurements quoted.
  • The magnifier drifts on its own on a touchscreen. With no pointer to follow it would sit in the centre for the whole visit; a 22 s animation walks it around instead.
  • The links point to anchors on this page. The original is a multi-page site; here everything leads back to an existing section rather than to a 404.
  • The images are royalty-free: the eight photographs and the six drawings were produced for this template and can be redistributed without restriction and without attribution. Only the fonts keep their own licence — Barlow and Barlow Condensed are under the SIL Open Font Licence 1.1, whose text ships in fonts/OFL.txt.

Take it, open it, break it.

Corvella is free. The full library — the other templates and the components — comes with the subscription, alongside the course.

Immediate access · No commitment · Cancel in one click