Surf Report Template

A simple template of a weekly surf report with an animated SVG graph and a sliding content panel. The layout is powered by flexbox and viewport units. Highly experimental.

Today we’d like to share a little template with you. This flexbox-based layout represents a weekly (5-day) surf report which shows some data of the day, like temperatures and information on waves. It is accompanied by an animating SVG graph that visualizes the wave data. When hovering over each day, a division of day periods becomes visible, each one showing relevant information depending on the time of the day. Additionally, when clicking on a live cam button, another content panel is slided into view. This panel shows an embedded Video with a live cam recording. We hope this little layout comes in handy for a column-based layout project or for your next animated SVG graph adventure.

Please note that this is highly experimental and lots of data is hard-coded. You could use it as a rough base to build your dynamic solution with it.

Attention: Many modern properties are in use here, like Flexbox and viewport units. Gritty browsers only!

The structure

The initial HTML structure for our layout is the following:

<main class="theme-1">
	<header class="codrops-header"><!-- ... --></header>
	<!-- live cam panel -->
	<div class="content content--cam">
		<div data-type="youtube" data-video-id="lqmNApZXnGM"></div>
		<button class="btn btn--close" aria-label="Close Live Cam">
			<svg class="icon icon--cross">
				<use xlink:href="#icon-cross"></use>
			</svg>
		</button>
	</div>
	<!-- graph panel -->
	<div class="content content--graph">
		<svg class="graph" viewBox="0 0 1440 800" preserveAspectRatio="none">
			<defs>
				<linearGradient id="gradient1">
					<stop offset="0%" stop-color="#1231bb" />
					<stop offset="100%" stop-color="#238DE0"  />
				</linearGradient>
				<linearGradient id="gradient2" x1="0" x2="0" y1="0" y2=".7" xlink:href="#gradient1"/>
			</defs>
		</svg>
	</div>
	<!-- Button for toggling the live cam content -->
	<button class="btn btn--cam btn--hidden">
		<svg class="icon icon--cam icon--btn">
			<use xlink:href="#icon-cam"></use>
		</svg>
		<span class="btn__text">Live Cam</span>
	</button>
</main>

This includes the two panels for the live cam view and the graph view. We are going to dynamically build the resting HTML; a division for the day slices, and the graph path data. Furthermore, we’re using Plyr.js to embed a YouTube video in the cam panel.

The resulting HTML is the following:

<main class="theme-1">
	<header class="codrops-header">
		
	</header>
	<div class="content content--cam">
		<!-- ... -->
	</div>
	<div class="content content--graph">
		<!-- all slices -->
		<div class="slices">
			<!-- single slice -->
			<div class="slice slice--state-sunny">
				<!-- weather states (show by toggling icons) -->
				<div class="wstate-wrap">
					<svg class="wstate wstate--sunny">
						<use xlink:href="#state-sunny" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--cloudy">
						<use xlink:href="#state-cloudy" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--partlycloudy">
						<use xlink:href="#state-partlycloudy" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--rain">
						<use xlink:href="#state-rain" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--thunders">
						<use xlink:href="#state-thunders" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--clearnight">
						<use xlink:href="#state-clearnight" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
					<svg class="wstate wstate--partlycloudynight">
						<use xlink:href="#state-partlycloudynight" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
					</svg>
				</div><!-- /wstate-wrap -->

				<!-- weather data -->

				<span class="slice__data slice__data--period slice__data--hidden">
					<svg class="icon icon--clock"><use xlink:href="#icon-clock" xmlns:xlink="http://www.w3.org/1999/xlink"></use></svg>
					<span class="slice__data slice__data--time"> </span>
				</span>

				<span class="slice__data slice__data--dateday">
					<span class="slice__data slice__data--day">Today</span>
					<span class="slice__data slice__data--date">11/21</span>
				</span>

				<span class="slice__data slice__data--air">
					<svg class="icon icon--thermometer"><use xlink:href="#icon-thermometer" xmlns:xlink="http://www.w3.org/1999/xlink"></use></svg>
					<span class="slice__data slice__data--temperature">28 °C</span>
				</span>

				<span class="slice__data slice__data--wind">
					<svg class="icon icon--direction" style="transform: rotate(136.183deg);"><use xlink:href="#icon-direction" xmlns:xlink="http://www.w3.org/1999/xlink"></use></svg>
					<span class="slice__data slice__data--wind-speed">3 km/h</span>
				</span>

				<span class="slice__data slice__data--swell">
					<svg class="icon icon--wave"><use xlink:href="#icon-wave" xmlns:xlink="http://www.w3.org/1999/xlink"></use></svg>
					<span class="slice__data slice__data--swell-height">2 m</span>
					<span class="slice__data slice__data--swell-period">14 s</span>
				</span>

				<span class="slice__data slice__data--water">
					<svg class="icon icon--thermometer"><use xlink:href="#icon-thermometer" xmlns:xlink="http://www.w3.org/1999/xlink"></use></svg>
					<span class="slice__data slice__data--temperature">22 °C</span>
				</span>

				<!-- Hover overlay -->
				<div class="slice__hover">
					<div></div>
					<div></div>
					<div></div>
					<div></div>
					<div></div>
					<div></div>
				</div>

			</div>

			<div class="slice slice--state-partlycloudy"><!-- ... --></div>
			<!-- ... other slices -->
		</div>

		<svg class="graph" preserveaspectratio="none" viewbox="0 0 1440 800">
			<defs>
				<lineargradient id="gradient1">
					<stop offset="0%" stop-color="#1231bb"></stop>
					<stop offset="100%" stop-color="#238DE0"></stop>
				</lineargradient>
				<lineargradient id="gradient2" x1="0" x2="0" xlink:href="#gradient1" xmlns:xlink="http://www.w3.org/1999/xlink" y1="0" y2=".7"></lineargradient>
			</defs>
			<!-- animated SVG path -->
			<path class="graph__path" d="..."></path>
		</svg>
		
	</div>
	<!-- Button for toggling the live cam content -->
	<button class="btn btn--cam">
		<svg class="icon icon--cam icon--btn">
			<use xlink:href="#icon-cam" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
		</svg>
		<span class="btn__text">Live Cam</span>
	</button>
</main>

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

Some interesting CSS

The interesting CSS is the part of the slices and slice data:

.slices {
	position: absolute;
	display: flex;
	width: 100%;
	height: 100vh;
}

.slice {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	width: 20vw;
	height: 100%;
	padding: 5em 0 0 0;
	pointer-events: none;
	background: linear-gradient(200deg, #a0cfe4, #e8c37e);
}

/* The daytime periods show individual backgrounds */
/* we've grouped them, but you can differentiate it even more */
.slice--period-1,
.slice--period-6 {
	background: linear-gradient(200deg, #6a8a98, #e8c37e);
}

.slice--period-2,
.slice--period-5 {
	background: linear-gradient(200deg, #8db7ca, #e8c37e);
}

.slice--period-3,
.slice--period-4 {
	background: linear-gradient(200deg, #a0cfe4, #e8c37e);
}

/* The slice data */
.slice__data {
	font-size: 1.25vw;
	line-height: 1.5;
	position: relative;
	z-index: 100;
	display: flex;
	padding: 1em;
}

.slice__data .slice__data {
	display: inline-block;
	padding: 0 0.5em 0 0;
	vertical-align: middle;
	white-space: nowrap;
}

.slice__data--hidden {
	opacity: 0;
}

.slice__data--dateday {
	color: #4682a5;
}

.slice__data--air,
.slice__data--wind,
.slice__data--water {
	color: #4682a5;
}

.slice__data--period,
.slice__data--swell {
	color: #fff;
}

.slice__data--swell {
	font-size: 1.5vw;
	margin-top: auto;
}

.slice__data--water {
	margin-top: auto;
}

.slice__data .icon {
	flex: none;
	margin: 0 0.5em 0 0;
}

/* The weather icons */
/* Depending on the state, we switch the visibility of the respective icon */
.wstate-wrap {
	font-size: 2em;
	position: absolute;
	z-index: 100;
	overflow: hidden;
	width: 100%;
	height: 100%;
	margin: 0;
}

.wstate {
	position: absolute;
	top: 0;
	right: -40%;
	width: 100%;
	max-height: 100%;
	opacity: 0;
}

.slice--state-sunny .wstate--sunny,
.slice--state-cloudy .wstate--cloudy,
.slice--state-partlycloudy .wstate--partlycloudy,
.slice--state-rain .wstate--rain,
.slice--state-thunders .wstate--thunders,
.slice--state-clearnight .wstate--clearnight,
.slice--state-partlycloudynight .wstate--partlycloudynight {
	opacity: 1;
}

/* Hover areas */

.slice__hover {
	position: absolute;
	z-index: 1000;
	top: 0;
	left: 0;
	display: flex;
	width: 100%;
	height: 100%;
	pointer-events: auto;
}

.slice__hover div {
	width: calc(100% / 6);
	height: 100%;
}

.slice__hover div:hover {
	background: rgba(0, 0, 0, 0.03);
}

All icons used in this template are included via SVG use. The icons are added to a hidden SVG as symbols in the beginning of the HTML.

We hope this template is somehow useful to you!

Browser Support:
  • ChromeSupported
  • FirefoxSupported
  • Internet ExplorerSupported from version E
  • SafariSupported
  • OperaSupported

References and Credits

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 18

Comments are closed.
  1. I feel like the Live Cam button could be much more prominent, didn’t even realise it was there until I read through the article and went searching. Otherwise, quite cool!

    • There is a site called magicseaweed which provides an API with a fair use policy of 1M request per month.

  2. Anyone know where to plugin an API from a API source like Magicseaweed or NOAA on this given code?

    • Thanks for letting us know! It was an HTTPS problem because of our recent switch. We’ve fixed it now 🙂 (you might need to do a hard reload).

  3. It’s great!!!
    But as rocky_nupt mentioned above, waves do not show up on Chrome.(I can see it on IE)
    On the other hand, Icons such as thermometor and wind-arrow do not show up in IE, but I can see it on Chrome.
    Is there anyone who can let me get advised how to fix it?