3 Essential Design Trends, February 2020

Designers are embracing big, bold concepts with oversized elements, bright color, and even a little rule-breaking. (The best part? Most of these trends seem to overlap somewhat.) Here’s what’s trending in design this month.

Homepage Headline Heroes

Homepage hero areas are shifting again from website entryways with plenty of text, CTAs, and options for users, to simple displays with big headlines (and maybe not much else).

Use of oversized headlines and text elements make it clear from the start what a website or design is about, but doesn’t provide a lot of opportunity for users to explore without scrolling. And that might be okay. Thanks to mobile dominance, users have become accustomed to the scroll. It may even be shifting to the preferred method of digesting content. (Even more than clicks or taps.)

Scroll is fast and allows users to glance at content and information with little delay or interaction.

Each of the website examples below are designed for just that:

Whiteboard opens with a large headline that encompasses their vision statement and nothing else. On scroll you get access to projects and a deeper dive into information about the brand.

Self-Evident Poems doesn’t actually scroll but moves into prompts for usability. It’s rooted in the same homepage headline hero area that’s designed to draw you into the content.

Illume has additional content below the scroll beneath a giant headline in the hero area. What this design does differently is that it does include some imagery, although it is still secondary to the text because of typography size.

Peachy Tones

Beat the Winter blues with a dose of Spring color! Peachy tones seem to be everywhere.

While this trend might be an evolution from other bright colors such as pinks and oranges that have been popular, it has a lot of practical application. Use it as a dominant color such as Grain & Mortar, and Monokai, or to create an accent like Kevin van der Wijst’s portfolio.

Peachy tones provide plenty of options and can be more pinkish or push toward orange. The color can be highly saturated or fairly pale. The nice thing about peachy tones is that they aren’t that overpowering, and work equally well as background or foreground color. Peach can get a little tricky when used for typographic elements, depending on the font style and contrasting elements.

Larger swaths of peach tend to stand up against other elements better than tiny ones. Note that even as an accent in the featured portfolio below, peach tones encompass a significant portion of the canvas. (You might also want to click through and play with that design, which also includes cool liquid animation. You can even make the peach area take up most of the screen.)

Outline Fonts

This trend is exploding in use from small projects to big brands. Outline fonts are a big deal. It’s one of those trends that you would shake your head at and say “no way” if you didn’t see it in action … and used so well.

Outline fonts can be a challenge. They create an effect that’s almost the opposite of the oversized typography in another trend mentioned here. But they do create an eye-catching effect that draws you into the words on screen.

Outline fonts are almost always paired with the same font filled. It creates and yin and yang effect that can help keep users reading longer and engaging with content. The contrast between and outline and filled font also put specific emphasis on the bolder element in the lettering pair.

The trick to making it work is not to get too crazy with the design and design outline fonts so that there’s plenty of contrast for the letters to remain readable.

Fitlab is the busiest of the examples of this trend with multiple use of outline fonts and even a quick-moving video roll. Put it all together and the emphasis is on “personal” training. It works.

Chilly Source uses an outline font for its brand name so that you get another intro to it without too much brand in your face. (The name is mentioned three time on the homepage.)

Vitesse Trucking uses outline text to tell you what they do throughout the design. Text is information but also serves as an art element with movement in the parallax-style scrolling design. Outline type elements mirror smaller filled words and even include some layering and overlays to keep the eyes moving. It’s an interesting use of this trend in an industry where you might not expect it.

Conclusion

I’ll be the first to admit, you probably won’t find me designing with a lot of peachy coloring. While it works for these projects, it’s not a favorite of mine.

On the flip side, I adore all the outline font options. It’s funky and provides depth to text elements that we haven’t seen a lot of. How about you? What design trends can you see yourself using in the coming months?

Source
p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

An Interview With Zach Leatherman: A SmashingConf Austin Speaker

An Interview With Zach Leatherman: A SmashingConf Austin Speaker

An Interview With Zach Leatherman: A SmashingConf Austin Speaker

Rachel Andrew

2020-02-03T10:30:00+00:00 2020-02-04T00:09:44+00:00

We are so excited to be bringing SmashingConf to a new city this year. We’re bringing you SmashingConf Austin and we have a fantastic line-up of speakers.

Check out this post, where we introduce our new venue of Austin and share an interview with Miriam Suzanne. This time we have an interview with Zach Leatherman.

Zach will be talking about type and font performance at SmashingConf Austin. See you there?

Zach is no stranger to the Smashing stage, and if you want to find out more about web fonts and loading strategies, you can watch his talk from SmashingConf London 2018, paired with a talk by Monica Dinculescu from SmashingConf Barcelona, “Web Fonts And Performance: SmashingConf Videos".

Also, take a look at some of the resources that Zach has made available on the subject in his archive of posts about web fonts. There is plenty to get you started, and I think you can agree that there is no-one better to help us understand the current state of font loading while we are in Austin!

Tickets Are On Sale Now!

If you want to join in the fun, tickets are on sale. Last year, we sold out three of our conferences well before the conference date, and popular workshops also fill up fast. Just saying!

Smashing Editorial (il)
Full Stack Panic

A new podcast from Sean Fioritto inspired by Joel Califa’s term “Full Stack Anxiety”.

… the little voice in your head says … “I should know all of this. Do I even know what I’m doing?” Why do web developers the world over feel like this?

There is an episode with Joel talking about it as well as other interesting angles like an episode with psychologist Dr. Sherry Walling.

The overall vibe is that of catharsis in that, hopefully, none of this matters as much as it seems like it might. I’d like to think we try to deliver that, through a bit of levity, on ShopTalk Show as well.

Oh hey and Panic started a podcast too, a must-subscribe from me as a long-time fan of all their interesting work.

Direct Link to ArticlePermalink

The post Full Stack Panic appeared first on CSS-Tricks.

Innovation Can’t Keep the Web Fast

Every so often, the fruits of innovation bear fruit in the form of improvements to the foundational layers of the web. In 2015, HTTP/2 became a published standard in an effort to update an aging protocol. This was was both necessary and overdue, as HTTP/1 rendered web performance as an arcane sort of discipline in the form of strange workarounds of its limitations. Though HTTP/2 proliferation isn’t absolute — and there are kinks yet to be worked out — I don’t think it’s a stretch to say the web is better off because of it.

Unfortunately, the rollout of HTTP/2 has presided over a 102% median increase of bytes transferred over mobile the last four years. If we look at the 90th percentile of that same dataset — because it’s really the long tail of performance we need to optimize for — we see an increase of 239%. From 2016 (PDF warning) to 2019, the average mobile download speed in the U.S. has increased by 73%. In Brazil and India, average mobile download speeds increased by 75% and 28%, respectively, in that same period of time.

While page weight alone doesn’t necessarily tell the whole story of the user experience, it is, at the very least, a loosely related phenomenon which threatens the collective user experience. The story that HTTPArchive tells through data acquired from the Chrome User Experience Export (CrUX) can be interpreted a number of different ways, but this one fact is steadfast and unrelenting: most metrics gleaned from CrUX over the last couple of years show little, if any improvement despite various improvements in browsers, the HTTP protocol, and the network itself.

Given these trends, all that can be said of the impact of these improvements at this point is that it has helped to stem the tide of our excesses, but precious little to reduce them. Despite every significant improvement to the underpinnings of the web and the networks we access it through, we continue to build for it in ways that suggest we’re content with the never-ending Jevons paradox in which we toil.

If we’re to make progress in making a faster web for everyone, we must recognize some of the impediments to that goal:

  1. The relentless desire to monetize every square inch of the web, as well as the army of third party vendors which fuel the research mandated by such fevered efforts.
  2. Workplace cultures that favor unrestrained feature-driven development. This practice adds to — but rarely takes away from — what we cram down the wire to users.
  3. Developer conveniences that make the job of the developer easier, but can place an increasing cost on the client.

Counter-intuitively, owners of mature codebases which embody some or all of these traits continue to take the same unsustainable path to profitability they always have. They do this at their own peril, rather than acknowledge the repeatedly established fact that performance-first development practices will do as much — or more — for their bottom line and the user experience.

It’s with this understanding that I’ve come to accept that our current approach to remedy poor performance largely consists of engineering techniques that stem from the ill effects of our business, product management, and engineering practices. We’re good at applying tourniquets, but not so good at sewing up deep wounds.

It’s becoming increasingly clear that web performance isn’t solely an engineering problem, but a problem of people. This is an unappealing assessment in part because technical solutions are comparably inarguable. Content compression works. Minification works. Tree shaking works. Code splitting works. They’re undeniably effective solutions to what may seem like entirely technical problems.

The intersection of web performance and people, on the other hand, is messy and inconvenient. Unlike a technical solution as clearly beneficial as HTTP/2, how do we qualify what successful performance cultures look like? How do we qualify successful approaches to get there? I don’t know exactly what that looks like, but I believe a good template is the following marriage of cultural and engineering tenets:

  1. An organization can’t be successful in prioritizing performance if it can’t secure the support of its leaders. Without that crucial element, it becomes extremely difficult for organizations to create a culture in which performance is the primary feature of their product.
  2. Even with leadership support, performance can’t be effectively prioritized if the telemetry isn’t in place to measure it. Without measurement, it becomes impossible to explain how product development affects performance. If you don’t have the numbers, no one will care about performance until it becomes an apparent crisis.
  3. When you have the support of leadership to make performance a priority and the telemetry in place to measure it, you still can’t get there unless your entire organization understands web performance. This is the time at which you develop and roll out training, documentation, best practices, and standards the organization can embrace. In some ways, this is the space which organizations have already spent a lot of time in, but the challenging work is in establishing feedback loops to assess how well they understand and have applied that knowledge.
  4. When all of the other pieces are finally in place, you can start to create accountability in the organization around performance. Accountability doesn’t come in the form of reprisals when your telemetry tells you performance has suffered over time, but rather in the form of guard rails put in place in the deployment process to alert you when thresholds have been crossed.

Now comes the kicker: even if all of these things come together in your workplace, good outcomes aren’t guaranteed. Barring some regulation that forces us to address the poorly performing websites in our charge — akin to how the ADA keeps us on our toes with regard to accessibility — it’s going to take continuing evangelism and pressure to ensure performance remains a priority. Like so much of the work we do on the web, the work of maintaining a good user experience in evolving codebases is never done. I hope 2020 is the year that we meaningfully recognize that performance is about people, and adapt accordingly.

As technological innovations such as HTTP/3 and 5G emerge, we must take care not to rest on our laurels and simply assume they will heal our ills once and for all. If we do, we’ll certainly be having this discussion again when the successors to those technologies loom. Innovation alone can’t keep the web fast because making the web fast — and keeping it that way — is the hard work we can only accomplish by working together.

The post Innovation Can’t Keep the Web Fast appeared first on CSS-Tricks.

Smaller HTML Payloads with Service Workers

Short story: Philip Walton has a clever idea for using service workers to cache the top and bottom of HTML files, reducing a lot of network weight.

Longer thoughts: When you’re building a really simple website, you can get away with literally writing raw HTML. It doesn’t take long to need a bit more abstraction than that. Even if you’re building a three-page site, that’s three HTML files, and your programmer’s mind will be looking for ways to not repeat yourself. You’ll probably find a way to “include” all the stuff at the top and bottom of the HTML, and just change the content in the middle.

I have tended to reach for PHP for that sort of thing in the past (<?php include('header.php); ?>), although these days I’m feeling much more Jamstack-y and I’d probably do it with Eleventy and Nunjucks.

Or, you could go down the SPA (Single Page App) route just for this basic abstraction if you want. Next and Nuxt are perhaps a little heavy-handed for a few includes, but hey, at least they are easy to work with and the result is a nice static site. The thing about these JavaScript-powered SPA frameworks (Gatsby is in here, too), is that they “hydrate” from static sites into SPAs as the JavaScript loads. Part of the reason for that is speed. No longer does the browser need to reload and request a whole big HTML page again to render; it just asks for whatever smaller amount of data it needs and replaces it on the fly.

So in a sense, you might build a SPA because you have a common header and footer and just want to replace the guts, for efficiencies sake.

Here’s Phil:

In a traditional client-server setup, the server always needs to send a full HTML page to the client for every request (otherwise the response would be invalid). But when you think about it, that’s pretty wasteful. Most sites on the internet have a lot of repetition in their HTML payloads because their pages share a lot of common elements (e.g. the <head>, navigation bars, banners, sidebars, footers etc.). But in an ideal world, you wouldn’t have to send so much of the same HTML, over and over again, with every single page request.

With service workers, there’s a solution to this problem. A service worker can request just the bare minimum of data it needs from the server (e.g. an HTML content partial, a Markdown file, JSON data, etc.), and then it can programmatically transform that data into a full HTML document.

So rather than PHP, Eleventy, a JavaScript framework, or any other solution, Phil’s idea is that a service worker (a native browser technology) can save a cache of a site’s header and footer. Then server requests only need to be made for the “guts” while the full HTML document can be created on the fly.

It’s a super fancy idea, and no joke to implement, but the fact that it could be done with less tooling might be appealing to some. On Phil’s site:

 on this site over the past 30 days, page loads from a service worker had a 47.6% smaller network payloads, and a median First Contentful Paint (FCP) that was 52.3% faster than page loads without a service worker (416ms vs. 851ms).

Aside from configuring a service worker, I’d think the most finicky part is having to configure your server/API to deliver a content-only version of your stuff or build two flat file versions of everything.

Direct Link to ArticlePermalink

The post Smaller HTML Payloads with Service Workers appeared first on CSS-Tricks.

29 Days Of February (2020 Wallpapers Edition)

29 Days Of February (2020 Wallpapers Edition)

29 Days Of February (2020 Wallpapers Edition)

Cosima Mielke

2020-01-31T11:00:00+00:00 2020-02-01T00:08:37+00:00

What will you make of the extra day that February has in store for us this year? Visit an old friend, explore a new place, or use it to get stuff done you have put off for so long? Whatever you might have planned this month, our new collection of wallpapers is bound to cater for a little inspiration spark along the way.

Created by artists and designers from all across the globe, the wallpapers come in versions with and without a calendar for February 2020 and can be downloaded for free — a Smashing tradition that has been going on for more than nine years already. A big thank-you to everyone who challenged their creative skills and shared their artworks with us this time around!

As a little bonus goodie, we also added some February favorites from our archives to the end of this post. Because, well, some things are just too good to be forgotten, right? Enjoy!

Please note that:

  • All images can be clicked on and lead to the preview of the wallpaper,
  • We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.

Submit your wallpaper

Do you have an idea for a March wallpaper design? We are always looking for creative talent to be featured in our wallpapers posts. Don’t be shy, join in! →

It’s A Cupcake Kind Of Day!

“Sprinkles are fun, festive and filled with love… especially when topped on a cupcake! Everyone is creative in their own unique way, so why not try baking some cupcakes and decorating them for your sweetie this month? Something homemade, like a cupcake or DIY craft is always a sweet gesture.” — Designed by Artsy Cupcake from the United States.

It’s A Cupcake Kind Of Day!

Well It’s Groundhog Day… Again!

“‘It’s always Groundhog Day and there’s nothing I can do about it.’ as the inimitable Bill Murray said in the timeless Groundhog Day movie. We used a photo manipulation technique to come up with this sense of being caught in a time loop. When the Groundhog emerges from his den on this Groundhog day, will it forecast an early Spring or six more weeks of winter? Find out on February 2nd!” — Designed by Alistair Dodds from the United Kingdom.

Well It’s Groundhog Day… Again!

Love Is in the Air

— Designed by MasterBundles from the United States.

Love Is in the Air

National Don’t Cry Over Spilled Milk Day

“If ‘don’t cry over spilled milk’ hasn’t yet been your mantra, it should definitely become now. The English proverb, whose national day is celebrated on February 11th, stands as a reminder not to worry over things of the past that cannot be undone, but to think positive, and keep our spirits high. Life is too short to let the trifling issues bother us.” — Designed by Pop Art Studio from Serbia.

National Don’t Cry Over Spilled Milk Day

The Rainbow Is Here!

“In February the weather is crazy. One day it is sunny and the next it is snowing. And that is its charm…” — Designed by Veronica Valenzuela from Spain.

The Rainbow Is Here!

Freedom

“On the 24th of February, far north in Europe, the tiny nation of Estonia celebrates its 102nd Independence Day. Cheers to the cleanest, greenest nation on earth! Happy Independence Day Estonia! Mu isamaa, mu õnn ja rõõm — My fatherland, my joy and happiness.” — Designed by Shishir Keluskar from Tallinn.

Freedom

Rock & Roll

Designed by Ricardo Gimenes from Sweden.

Rock & Roll

Celebrate Love

“February brings the season of love, and what could be better than celebrating it with Taj Mahal – the iconic monument and symbol of love.” — Designed by Farhat Asif from India.

Celebrate Love

Oldies But Goodies

Do you know those moments when you rediscover a treasured item you almost forgot about? Below you’ll find some February wallpaper goodies from our archives. Maybe one of your favorites from the past is in there, too? (Please note that these wallpapers don’t come with a calendar.)

Savannah Stroll

“February is a month focused on romance and as a southerner, I can’t think of a more romantic way to spend a day than strolling the historic moss-draped streets of Savannah, GA. Spending time sitting on a bench on one of the many beautiful squares, holding hands and people watching as you sip a cappuccino.” — Designed by Heather Ozee Designs from the United States.

Savannah Stroll

Principles Of Good Design

“The simplicity seen in the work of Dieter Rams which has ensured his designs from the 50s and 60s still hold a strong appeal.” — — Designed by Vinu Chaitanya from India.

Principles of Good Design- Dieter Rams

Dark Temptation

“A dark romantic feel, walking through the city on a dark and rainy night.” — Designed by Matthew Talebi from the United States.

Dark Temptation

Cold And Frost

“Frosts in Russia are very severe. Walking through the Park, I found these branches at the top and decided to capture the moment.” — Designed by Nikolay Belikov from Russia.

Cold And Frost

Love Is Worth Fighting For

— Designed by Maria Keller from Mexico.

Love Is Worth Fighting For

Share The Same Orbit!

“I prepared a simple and chill layout design for February called ‘Share The Same Orbit!’ which suggests to share the love orbit.” — Designed by Valentin Keleti from Romania.

Share The Same Orbit!

Charlie Chaplin

“I love street art, so I took a shot of this great graffiti of Charlie Chaplin with his inspirational quote that is even more true for this age: ‘Sometimes we think too much and feel to little’. He also said: ‘More than machinery, we need humanity; more than cleverness, we need kindness and gentleness. Without these qualities, life will be violent and all will be lost.” — Designed by Marija Zaric from Belgrade, Serbia.

Charlie Chaplin

Plucking At The Heart Strings

“Choose to embrace Valentine’s as a day to appreciate those who are special to you. The base of this wallpaper is ‘Plucking at the Heart Strings’, an original painting by Hayden Gigner.” — Designed by Adam Mezzatesta from the United Kingdom.

Plucking At The Heart Strings

February Ferns

— Designed by Nathalie Ouederni from France.

February Ferns

French Fries

— Designed by Doreen Bethge from Germany.

French Fries

Snowy Sunset

— Designed by Nathalie Croze from France.

Snowy Sunset

Balloons

— Designed by Xenia Latii from Germany.

Balloons

February’s Gift

“A leap year means we have one more day to cherish! Maybe use it to visit an old friend, or go somewhere new, but use it well! And the most important: have some fun!” — — Designed by Printsome.com from the United Kingdom.

February’s Gift

Made In Japan

“See the beautiful colors, precision, and the nature of Japan in one picture.” — — Designed by Fatih Yilmaz from the Netherlands.

Made In Japan

February Flowers

“A little bit of romance, a little bit of vintage: Happy Valentine’s Day this month!” — Designed by Kari Andresen from the United States.

Smashing Wallpaper - february 13

Love Angel Vader

“Valentine’s Day is coming? Noooooooooooo!” — — Designed by Ricardo Gimenes from Sweden.

Love Angel Vader

Febrewery

“I live in Madison, WI USA, which is famous for its breweries. Wisconsin even named their baseball team ‘The Brewers.’ If you like beer, brats, and lots of cheese, it’s the place for you!” — — Designed by Danny Gugger from the United States.

Febrewery

Free Your Mind

“People should have the right to believe and think what they want. They should be free in choosing their opinion. The wallpaper (especially the birds) reminds me of the great freedom we have in many countries of the world.” — — Designed by Daniela Faltz from Germany.

Free Your Mind

Frozen Worlds

“A view of 2 frozen planets, lots of blue tints.” — Designed by Rutger Berghmans from Belgium.

Smashing Wallpaper - february 13

Join In Next Month!

Thank you to all designers for their participation. Join in next month!

Sticky Table of Contents with Scrolling Active States

Say you have a two-column layout: a main column with content. Say it has a lot of content, with sections that requires scrolling. And let’s toss in a sidebar column that is largely empty, such that you can safely put a position: sticky; table of contents over there for all that content in the main column. A fairly common pattern for documentation.

Bramus Van Damme has a nice tutorial on all this, starting from semantic markup, implementing most of the functionality with HTML and CSS, and then doing the last bit of active nav enhancement with JavaScript.

For example, if you don’t click yourself down to a section (where you might be able to get away with :target styling for active navigation), JavaScript is necessary to tell where you are scrolled to an highlight the active navigation. That active bit is handled nicely with IntersectionObserver, which is, like, the perfect API for this.

Here’s that result:

CodePen Embed Fallback

It reminds me of a very similar demo from Hakim El Hattab he called Progress Nav. The design pattern is exactly the same, but Hakim’s version has this ultra fancy SVG path that draws itself along the way, indenting for sub nav. I’ll embed a video here:

That one doesn’t use IntersectionObserver, so if you want to hack on this, combine ’em!

The post Sticky Table of Contents with Scrolling Active States appeared first on CSS-Tricks.

How To Create A Card Matching Game Using Angular And RxJS

How To Create A Card Matching Game Using Angular And RxJS

How To Create A Card Matching Game Using Angular And RxJS

Anna Prenzel

2020-01-30T13:00:00+00:00 2020-01-31T00:09:20+00:00

Today, I’d like to focus on data streams resulting from click events on the user interface. The processing of such clickstreams is particularly useful for applications with an intensive user interaction where many events have to be processed. I’d also like to introduce you to RxJS a bit more; it’s a JavaScript library that can be used to express event handling routines compactly and concisely in a reactive style.

What Are We Building?

Learning games and knowledge quizzes are popular both for younger and older users. An example is the game “pair matching”, where the user has to find related pairs in a mixture of images and/or text snippets.

The animation below shows a simple version of the game: The user selects two elements on the left and right side of the playing field one after the other, and in any order. Correctly matched pairs are moved to a separate area of the playing field, while any wrong assignments are immediately dissolved so that the user has to make a new selection.

Screen capture of the learningl game “matching pairs”
A sneak peek of the game we’ll be creating today

In this tutorial, we will build such a learning game step by step. In the first part, we will build an Angular component that is just showing the playing field of the game. Our aim is that the component can be configured for different use cases and target groups — from an animal quiz up to a vocabulary trainer in a language learning app. For this purpose, Angular offers the concept of content projection with customizable templates, which we will make use of. To illustrate the principle, I will build two versions of the game (“game1” and “game2”) with different layouts.

In the second part of the tutorial, we will focus on reactive programming. Whenever a pair is matched, the user needs to get some sort of feedback from the app; it is this event handling that is realized with the help of the library RxJS.

1. Building An Angular Component For The Learning Game

How To Create The Basic Framework

First, let’s create a new project named “learning-app”. With the Angular CLI, you can do this with the command ng new learning-app. In the file app.component.html, I replace the pre-generated source code as follows:

<div style="text-align:center"> <h1>Learning is fun!</h1>
</div>

In the next step, the component for the learning game is created. I’ve named it “matching-game” and used the command ng generate component matching-game. This will create a separate subfolder for the game component with the required HTML, CSS and Typescript files.

As already mentioned, the educational game must be configurable for different purposes. To demonstrate this, I create two additional components (game1 and game2) by using the same command. I add the game component as a child component by replacing the pre-generated code in the file game1.component.html or game2.component.html with the following tag:

<app-matching-game></app-matching-game>

At first, I only use the component game1. In order to make sure that game 1 is displayed immediately after starting the application, I add this tag to the app.component.html file:

<app-game1></app-game1>

When starting the application with ng serve --open, the browser will display the message “matching-game works”. (This is currently the only content of matching-game.component.html.)

Now, we need to test the data. In the /app folder, I create a file named pair.ts where I define the class Pair:

export class Pair { leftpart: string; rightpart: string; id: number;
}

A pair object comprises two related texts (leftpart and rightpart) and an ID.

The first game is supposed to be a species quiz in which species (e.g. dog) have to be assigned to the appropriate animal class (i.e. mammal).

In the file animals.ts, I define an array with test data:

import { Pair } from './pair';
export const ANIMALS: Pair[] = [ { id: 1, leftpart: 'dog', rightpart: 'mammal'}, { id: 2, leftpart: 'blickbird', rightpart: 'bird'}, { id: 3, leftpart: 'spider', rightpart: 'insect'}, { id: 4, leftpart: 'turtle', rightpart: 'reptile' }, { id: 5, leftpart: 'guppy', rightpart: 'fish'},
];

The component game1 needs access to our test data. They are stored in the property animals. The file game1.component.ts now has the following content:

import { Component, OnInit } from '@angular/core';
import { ANIMALS } from '../animals';
@Component({ selector: 'app-game1', templateUrl: './game1.component.html', styleUrls: ['./game1.component.css']
})
export class Game1Component implements OnInit { animals = ANIMALS; constructor() { } ngOnInit() { }
}

The First Version Of The Game Component

Our next goal: The game component matching-game has to accept the game data from the parent component (e.g. game1) as input. The input is an array of “pair” objects. The user interface of the game should be initialized with the passed objects when starting the application.

Screen capture of the learningl game “matching pairs”

For this purpose, we need to proceed as follows:

  1. Add the property pairs to the game component using the @Input decorator.
  2. Add the arrays solvedPairs and unsolvedPairs as additional private properties of the component. (It is necessary to distinguish between already “solved” and “not yet solved” pairs.)
  3. When the application is started (see function ngOnInit) all pairs are still “unsolved” and are therefore moved to the array unsolvedPairs.
import { Component, OnInit, Input } from '@angular/core';
import { Pair } from '../pair';
@Component({ selector: 'app-matching-game', templateUrl: './matching-game.component.html', styleUrls: ['./matching-game.component.css']
}) export class MatchingGameComponent implements OnInit { @Input() pairs: Pair[]; private solvedPairs: Pair[] = []; private unsolvedPairs: Pair[] = []; constructor() { } ngOnInit() { for(let i=0; i<this.pairs.length; i++){ this.unsolvedPairs.push(this.pairs[i]); } }
}

Furthermore, I define the HTML template of the matching-game component. There are containers for the unsolved and solved pairs. The ngIf directive ensures that the respective container is only displayed if at least one unsolved or solved pair exists.

In the container for the unsolved pairs (class container unsolved), first all left (see the left frame in the GIF above) and then all right (see the right frame in the GIF) components of the pairs are listed. (I use the ngFor directive to list the pairs.) At the moment, a simple button is sufficient as a template.

With the template expression {{{pair.leftpart}} and {{{pair.rightpart}}}, the values of the properties leftpart and rightpart of the individual pair objects are queried when iterating the pair array. They are used as labels for the generated buttons.

The assigned pairs are listed in the second container (class container solved). A green bar (class connector) indicates that they belong together.

The corresponding CSS code of the file matching-game.component.css can be found in the source code at the beginning of the article.

<div id="game"> <div class="container unsolved" *ngIf="unsolvedPairs.length>0"> <div class="pair_items left"> <button *ngFor="let pair of unsolvedPairs" class="item"> {{pair.leftpart}} </button> </div> <div class="pair_items right"> <button *ngFor="let pair of unsolvedPairs" class="item"> {{pair.rightpart}} </button> </div> </div> <div class="container solved" *ngIf="solvedPairs.length>0"> <div *ngFor="let pair of solvedPairs" class="pair"> <button>{{pair.leftpart}}</button> <div class="connector"></div> <button>{{pair.rightpart}}</button> </div> </div>
</div>

In the component game1, the array animals is now bound to the pairs property of the component matching-game (one-way data binding).

<app-matching-game [pairs]="animals"></app-matching-game>

The result is shown in the image below.

Current state of the user interface
Current state of the user interface

Obviously, our matching game is not too difficult yet, because the left and right parts of the pairs are directly opposite each other. So that the pairing is not too trivial, the right parts should be mixed. I solve the problem with a self-defined pipe shuffle, which I apply to the array unsolvedPairs on the right side (the parameter test is needed later to force the pipe to be updated):

...
<div class="pair_items right"> <button *ngFor="let pair of unsolvedPairs | shuffle:test" class="item"> {{pair.rightpart}} </button> </div>
...

The source code of the pipe is stored in the file shuffle.pipe.ts in the app folder (see source code at the beginning of the article). Also note the file app.module.ts, where the pipe must be imported and listed in the module declarations. Now the desired view appears in the browser.

Extended Version: Using Customizable Templates To Allow An Individual Design Of The Game

Instead of a button, it should be possible to specify arbitrary template snippets to customize the game. In the file matching-game.component.html I replace the button template for the left and right side of the game with an ng-template tag. I then assign the name of a template reference to the property ngTemplateOutlet. This gives me two placeholders, which are replaced by the content of the respective template reference when rendering the view.

We are here dealing with the concept of content projection: certain parts of the component template are given from outside and are “projected” into the template at the marked positions.

When generating the view, Angular must insert the game data into the template. With the parameter ngTemplateOutletContext I tell Angular that a variable contextPair is used within the template, which should be assigned the current value of the pair variable from the ngFor directive.

The following listing shows the replacement for the container unsolved. In the container solved, the buttons have to be replaced by the ng-template tags as well.

<div class="container unsolved" *ngIf="unsolvedPairs.length>0">
<div class="pair_items left"> <div *ngFor="let pair of unsolvedPairs" class="item"> <ng-template [ngTemplateOutlet]="leftpart_temp" [ngTemplateOutletContext]="{contextPair: pair}"> </ng-template> </div> </div> <div class="pair_items right"> <div *ngFor="let pair of unsolvedPairs | shuffle:test" class="item"> <ng-template [ngTemplateOutlet]="leftpart_temp" [ngTemplateOutletContext]="{contextPair: pair}"> </ng-template> </div>
</div>
</div>
...

In the file matching-game.component.ts, the variables of both template references (leftpart_temp and rightpart_temp) must be declared. The decorator @ContentChild indicates that this is a content projection, i.e. Angular now expects that the two template snippets with the respective selector (leftpart or rightpart) are provided in the parent component between the tags <app-matching-game></app-matching-game> of the host element (see @ViewChild).

@ContentChild('leftpart', {static: false}) leftpart_temp: TemplateRef<any>;
@ContentChild('rightpart', {static: false}) rightpart_temp: TemplateRef<any>;

Don’t forget: The types ContentChild and TemplateRef must be imported from the core package.

In the parent component game1, the two required template snippets with the selectors leftpart and rightpart are now inserted.

For the sake of simplicity, I will reuse the buttons here again:

<app-matching-game [pairs]="animals"> <ng-template #leftpart let-animalPair="contextPair"> <button>{{animalPair.leftpart}}</button> </ng-template> <ng-template #rightpart let-animalPair="contextPair"> <button>{{animalPair.rightpart}}</button> </ng-template>
</app-matching-game>

The attribute let-animalPair="contextPair" is used to specify that the context variable contextPair is used in the template snippet with the name animalPair.

The template snippets can now be changed to your own taste. To demonstrate this I use the component game2. The file game2.component.ts gets the same content as game1.component.ts. In game2.component.html I use an individually designed div element instead of a button. The CSS classes are stored in the file game2.component.css.

<app-matching-game [pairs]="animals"> <ng-template #leftpart let-animalPair="contextPair"> <div class="myAnimal left">{{animalPair.leftpart}}</div> </ng-template> <ng-template #rightpart let-animalPair="contextPair"> <div class="myAnimal right">{{animalPair.rightpart}}</div> </ng-template>
</app-matching-game>

After adding the tags <app-game2></app-game2> on the homepage app.component.html, the second version of the game appears when I start the application:

An alternative view of the game in the component game2
An alternative view of the game in the component game2

The design possibilities are now almost unlimited. It would be possible, for example, to define a subclass of Pair that contains additional properties. For example, image addresses could be stored for the left and/or right parts. The images could be displayed in the template along with the text or instead of the text.

2. Control Of User Interaction With RxJS

Advantages Of Reactive Programming With RxJS

To turn the application into an interactive game, the events (e.g. mouse click events) that are triggered at the user interface must be processed. In reactive programming, continuous sequences of events, so-called “streams”, are considered. A stream can be observed (it is an “observable”), i.e. there can be one or more “observers” or “subscribers” subscribing to the stream. They are notified (usually asynchronously) about every new value in the stream and can react to it in a certain way.

With this approach, a low level of coupling between the parts of an application can be achieved. The existing observers and observables are independent of each other and their coupling can be varied at runtime.

The JavaScript library RxJS provides a mature implementation of the Observer design pattern. Furthermore, RxJS contains numerous operators to convert streams (e.g. filter, map) or to combine them into new streams (e.g. merge, concat). The operators are “pure functions” in the sense of functional programming: They do not produce side effects and are independent of the state outside the function. A program logic composed only of calls to pure functions does not need global or local auxiliary variables to store intermediate states. This, in turn, promotes the creation of stateless and loosely coupled code blocks. It is therefore desirable to realize a large part of the event handling by a clever combination of stream operators. Examples of this are given in the section after next, based on our matching game.

Integrating RxJS Into The Event Handling Of An Angular Component

The Angular framework works with the classes of the RxJS library. RxJS is therefore automatically installed when Angular is installed.

The image below shows the main classes and functions that play a role in our considerations:

A model of the essential classes for event handling in Angular/RxJS
A model of the essential classes for event handling in Angular/RxJS
Class NameFunction
Observable (RxJS)Base class that represents a stream; in other words, a continuous sequence of data. An observable can be subscribed to. The pipe function is used to apply one or more operator functions to the observable instance.
Subject (RxJS)The subclass of observable provides the next function to publish new data in the stream.
EventEmitter (Angular)This is an angular-specific subclass that is usually only used in conjunction with the @Output decorator to define a component output. Like the next function, the emit function is used to send data to the subscribers.
Subscription (RxJS)The subscribe function of an observable returns a subscription instance. It is required to cancel the subscription after using the component.

With the help of these classes, we want to implement the user interaction in our game. The first step is to make sure that an element that is selected by the user on the left or right side is visually highlighted.

The visual representation of the elements is controlled by the two template snippets in the parent component. The decision how they are displayed in the selected state should therefore also be left to the parent component. It should receive appropriate signals as soon as a selection is made on the left or right side or as soon as a selection is to be undone.

For this purpose, I define four output values of type EventEmitter in the matching-game.component.ts file. The types Output and EventEmitter have to be imported from the core package.

@Output() leftpartSelected = new EventEmitter<number>();
@Output() rightpartSelected = new EventEmitter<number>();
@Output() leftpartUnselected = new EventEmitter();
@Output() rightpartUnselected = new EventEmitter();

In the template matching-game.component.html, I react to the mousedown event on the left and right side, and then send the ID of the selected item to all receivers.

<div *ngFor="let pair of unsolvedPairs" class="item" (mousedown)="leftpartSelected.emit(pair.id)">
...
<div *ngFor="let pair of unsolvedPairs | shuffle:test" class="item" (mousedown)="rightpartSelected.emit(pair.id)">

In our case, the receivers are the components game1 and game2. There you can now define the event handling for the events leftpartSelected, rightpartSelected, leftpartUnselected and rightpartUnselected. The variable $event represents the emitted output value, in our case the ID. In the following you can see the listing for game1.component.html, for game2.component.html the same changes apply.

<app-matching-game [pairs]="animals" (leftpartSelected)="onLeftpartSelected($event)" (rightpartSelected)="onRightpartSelected($event)" (leftpartUnselected)="onLeftpartUnselected()" (rightpartUnselected)="onRightpartUnselected()"> <ng-template #leftpart let-animalPair="contextPair"> <button [class.selected]="leftpartSelectedId==animalPair.id"> {{animalPair.leftpart}} </button> </ng-template> <ng-template #rightpart let-animalPair="contextPair"> <button [class.selected]="rightpartSelectedId==animalPair.id"> {{animalPair.rightpart}} </button> </ng-template>
</app-matching-game>

In game1.component.ts (and similarly in game2.component.ts), the event handler functions are now implemented. I store the IDs of the selected elements. In the HTML template (see above), these elements are assigned the class selected. The CSS file game1.component.css defines which visual changes this class will bring about (e.g. color or font changes). Resetting the selection (unselect) is based on the assumption that the pair objects always have positive IDs.

onLeftpartSelected(id:number):void{ this.leftpartSelectedId = id;
}
onRightpartSelected(id:number):void{ this.rightpartSelectedId = id;
}
onLeftpartUnselected():void{ this.leftpartSelectedId = -1;
}
onRightpartUnselected():void{ this.rightpartSelectedId = -1;
}

In the next step, event handling is required in the matching game component. It must be determined if an assignment is correct, that is, if the left selected element matches the right selected element. In this case, the assigned pair can be moved into the container for the resolved pairs.

I would like to formulate the evaluation logic using RxJS operators (see the next section). For preparation, I create a subject assignmentStream in matching-game.component.ts. It should emit the elements selected by the user on the left or right side. The goal is to use RxJS operators to modify and split the stream in such a way that I get two new streams: one stream solvedStream which provides the correctly assigned pairs and a second stream failedStream which provides the wrong assignments. I would like to subscribe to these two streams with subscribe in order to be able to perform appropriate event handling in each case.

I also need a reference to the created subscription objects, so that I can cancel the subscriptions with “unsubscribe” when leaving the game (see ngOnDestroy). The classes Subject and Subscription must be imported from the package “rxjs”.

private assignmentStream = new Subject(); private solvedStream = new Observable<Pair>();
private failedStream = new Observable<string>(); private s_Subscription: Subscription;
private f_Subscription: Subscription; ngOnInit(){ ... //TODO: apply stream-operators on //leftpartClicked und rightpartClicked this.s_Subscription = this.solvedStream.subscribe(pair => handleSolvedAssignment(pair)); this.f_Subscription = this.failedStream.subscribe(() => handleFailedAssignment());
} ngOnDestroy() { this.s_Subscription.unsubscribe(); this.f_Subscription.unsubscribe();
}

If the assignment is correct, the following steps are done:

  • The assigned pair is moved to the container for the solved pairs.
  • The events leftpartUnselected and rightpartUnselected are sent to the parent component.

No pair is moved if the assignment is incorrect. If the wrong assignment was executed from left to right (side1 has the value left), the selection should be undone for the element on the left side (see the GIF at the beginning of the article). If an assignment is made from right to left, the selection is undone for the element on the right side. This means that the last element that was clicked on remains in a selected state.

For both cases, I prepare the corresponding handler functions handleSolvedAssignment and handleFailedAssignment (remove function: see source code at the end of this article):

private handleSolvedAssignment(pair: Pair):void{ this.solvedPairs.push(pair); this.remove(this.unsolvedPairs, pair); this.leftpartUnselected.emit(); this.rightpartUnselected.emit(); //workaround to force update of the shuffle pipe this.test = Math.random() * 10;
}
private handleFailedAssignment(side1: string):void{ if(side1=="left"){ this.leftpartUnselected.emit(); }else{ this.rightpartUnselected.emit(); } }

Now we have to change the viewpoint from the consumer who subscribes to the data to the producer who generates the data. In the file matching-game.component.html, I make sure that when clicking on an element, the associated pair object is pushed into the stream assignmentStream. It makes sense to use a common stream for the left and right side because the order of the assignment is not important for us.

<div *ngFor="let pair of unsolvedPairs" class="item" (mousedown)="leftpartSelected.emit(pair.id)"
(click)="assignmentStream.next({pair: pair, side: 'left'})">
...
<div *ngFor="let pair of unsolvedPairs | shuffle:test" class="item" (mousedown)="rightpartSelected.emit(pair.id)" (click)="assignmentStream.next({pair: pair, side: 'right'})">

Design Of The Game Interaction With RxJS Operators

All that remains is to convert the stream assignmentStream into the streams solvedStream and failedStream. I apply the following operators in sequence:

pairwise

There are always two pairs in an assignment. The pairwise operator picks the data in pairs from the stream. The current value and the previous value are combined into a pair.

From the following stream…

„{pair1, left}, {pair3, right}, {pair2, left}, {pair2, right}, {pair1, left}, {pair1, right}“

…results this new stream:

„({pair1, left}, {pair3, right}), ({pair3, right}, {pair2, left}), ({pair2, left}, {pair2, right}), ({pair2, right}, {pair1, left}), ({pair1, left}, {pair1, right})“ 

For example, we get the combination ({pair1, left}, {pair3, right}) when the user selects dog (id=1) on the left side and insect (id=3) on the right side (see array ANIMALS at the beginning of the article). These and the other combinations result from the game sequence shown in the GIF above.

filter

You have to remove all combinations from the stream that were made on the same side of the playing field like ({pair1, left}, {pair1, left}) or ({pair1, left}, {pair4, left}).

The filter condition for a combination comb is therefore comb[0].side != comb[1].side.

partition

This operator takes a stream and a condition and creates two streams from this. The first stream contains the data that meets the condition and the second stream contains the remaining data. In our case, the streams should contain correct or incorrect assignments. So the condition for a combination comb is comb[0].pair===comb[1].pair.

The example results in a „correct” stream with

({pair2, left}, {pair2, right}), ({pair1, left}, {pair1, right}) 

and a “wrong” stream with

({pair1, left}, {pair3, right}), ({pair3, right}, {pair2, left}), ({pair2, right}, {pair1, left}) 

map

Only the individual pair object is required for further processing of a correct assignment, such as pair2. The map operator can be used to express that the combination comb should be mapped to comb[0].pair. If the assignment is incorrect, the combination comb is mapped to the string comb[0].side because the selection should be reset on the side specified by side.

The pipe function is used to concatenate the above operators. The operators pairwise, filter, partition, map must be imported from the package rxjs/operators.

ngOnInit() { ... const stream = this.assignmentStream.pipe( pairwise(), filter(comb => comb[0].side != comb[1].side) ); //pipe notation leads to an error message (Angular 8.2.2, RxJS 6.4.0) const [stream1, stream2] = partition(comb => comb[0].pair === comb[1].pair)(stream); this.solvedStream = stream1.pipe( map(comb => comb[0].pair) ); this.failedStream = stream2.pipe( map(comb => comb[0].side) ); this.s_Subscription = this.solvedStream.subscribe(pair => this.handleSolvedAssignment(pair)); this.f_Subscription = this.failedStream.subscribe(side => this.handleFailedAssignment(side));
}

Now the game already works!

Screen capture of the learningl game “matching pairs”
Final result

By using the operators, the game logic could be described declaratively. We only described the properties of our two target streams (combined into pairs, filtered, partitioned, remapped) and did not have to worry about the implementation of these operations. If we had implemented them ourselves, we would also have had to store intermediate states in the component (e.g. references to the last clicked items on the left and right side). Instead, the RxJS operators encapsulate the implementation logic and the required states for us and thus raise the programming to a higher level of abstraction.

Conclusion

Using a simple learning game as an example, we tested the use of RxJS in an Angular component. The reactive approach is well suited to process events that occur on the user interface. With RxJS, the data needed for event handling can be conveniently arranged as streams. Numerous operators, such as filter, map or partition are available for transforming the streams. The resulting streams contain data that is prepared in its final form and can be subscribed to directly. It requires a little skill and experience to select the appropriate operators for the respective case and to link them efficiently. This article should provide an introduction to this.

Further Resources

Related Reading on SmashingMag:

Smashing Editorial (ra, il)
20 Freshest Web Designs, January 2020

January 2020 is picking up where 2019 left off, with lots of animation and even more bold, bright color schemes. We’re also seeing an unusual number of luxury sites this month, and as always there’s a strong set of startups trying to break into the market. Enjoy!

Plink

To take on giants like PayPal, you need a compelling brand and a simple message, that can also wow with its first impression. Plink hits the nail on the head with its 3D animation.

Madame Turfu

Are you wondering what 2020 will hold for you? Why wait to find out when Madame Turfu can predict the future with this wonderfully fun set of digital tarot cards.

Nathan Taylor

What’s not to love about Nathan Taylor’s playful site? There’s so much to explore and do, but our favorite part is the different lighting modes.

Meatable

Selling Meatable is a tough prospect; it’s real meat, grown in a lab instead of taken by animal slaughter. The simple step-by-step site does a great job of explaining.

Sussex Royal

Whatever your view of Harry and Megan, there’s little doubt that their website oozes class. For a promotional site that isn’t actually selling anything, it’s a strong presence.

Emotive Feels

This fantastic manifesto from design agency Emotive Brand illustrates an A–Z of potential brand emotions with simple animations that would grace the cover of a Bluenote release.

UN\REAL

Swiss design agency UN\REAL’s site is a wonderfully chaotic love affair with web animation. It’s the type of site we can click around for hours, enjoying the sharp transitions.

Kate Jackling

Sometimes the best design takes a step back and allows its subject to bask in all the attention. Kate Jackling’s site does this, letting her gorgeous photography take center stage.

Helias

Helias has fully embraced the blob trend with a flood-filled area of color supporting each of its various products. It’s appropriate, engaging, and breaks up the formal grid well.

Klokki

Sometimes the hardest sites to design, are the ones for products about which there’s very little to say. Klokki is one such product, but its site is bold, confident, and persuasive.

Jonnie Hallman

Jonnie Hallman’s simple résumé site benefits greatly from the household names he’s worked for. We really like the details, like the way the monogram changes color as you scroll.

eaast

eaast is a design and development partnership from Paris that’s fully embraced the Memphis style. Their simple site proves you don’t need years’ worth of work to sell yourself.

Pantheone Audio

Proving that elegant scrolling is still very much a thing in 2020, Pantheone Audio uses the scroll to seamlessly navigate a luxurious site with a complex grid underpinning it.

Leaf

After decades of the best a man can get, the half of the species that shaves daily seems to be obsessed with reinventing the process. Leaf taps into that simple marketing approach.

Mociun

Most sites that sell jewelry miss the spirit of the pieces by focusing on the financial value. Mocuin gets it right with an on-trend color palette and stunning product photography.

Jon Way

Jon Way’s portfolio features work from over a decade of art direction. There’s a clear, consistent aesthetic thanks to a lovely ‘static’ effect that plays across the whole site.

Kota Yamaji

There’s some amazing work in Kato Yamaji’s portfolio, but what really strikes home is the amount of color he manages to squeeze in.

Robb Owen

We’ve seen lots of animated vector avatars over the last couple of years, but rarely do we see one with as much personality as Robb Owen’s. The cursor tracking makes it feel real.

Glasgow International Festival 2020

The Glasgow International Festival takes place between 24th April and 10th May 2020. Its site features some distinctly celtic typography, and tons of bold color.

Megababe

Megababe is taking on the beauty industry with a range of body products that are insanely popular, and as positive as its super-confident sales site.

Source
p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

How Do You Do max-font-size in CSS?

CSS doesn’t have max-font-size, so if we need something that does something along those lines, we have to get tricky.

Why would you need it at all? Well, font-size itself can be set in dynamic ways. For example, font-size: 10vw;. That’s using “viewport units” to size the type, which will get larger and smaller with the size of the browser window. If we had max-font-size, we could limit how big it gets (similarly the other direction with min-font-size).

One solution is to use a media query at a certain screen size breakpoint that sets the font size in a non-relative unit.

body { font-size: 3vw;
}
@media screen and (min-width: 1600px) { body { font-size: 30px; }
}

There is a concept dubbed CSS locks that gets fancier here, slowly scaling a value between a minimum and maximum. We’ve covered that. It can be like…

body { font-size: 16px;
}
@media screen and (min-width: 320px) { body { font-size: calc(16px + 6 * ((100vw - 320px) / 680)); }
}
@media screen and (min-width: 1000px) { body { font-size: 22px; }
}

We’ve also covered how it’s gotten (or will get) a lot simpler.

There is a max() function in CSS, so our example above becomes a one-liner:

font-size: max(30vw, 30px);

Or double it up with a min and max:

font-size: min(max(16px, 4vw), 22px);

Which is identical to:

font-size: clamp(16px, 4vw, 22px);

Browser compatibility for these functions is pretty sparse as I’m writing this, but Chrome currently has it. It will get there, but look at the first option in this article if you need it right now.

Now that we have these functions, it seems unlikely to me we’ll ever get min-font-size and max-font-size in CSS, since the functions are almost more clear as-is.

The post How Do You Do max-font-size in CSS? appeared first on CSS-Tricks.

Privacy Settings
We use cookies to enhance your experience while using our website. If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. We also use content and scripts from third parties that may use tracking technologies. You can selectively provide your consent below to allow such third party embeds. For complete information about the cookies we use, data we collect and how we process them, please check our Privacy Policy
Youtube
Consent to display content from Youtube
Vimeo
Consent to display content from Vimeo
Google Maps
Consent to display content from Google