Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update hero with flag animation (fixes #15515 and #15597) #15525

Merged
merged 12 commits into from
Dec 4, 2024
Merged
6 changes: 6 additions & 0 deletions bedrock/mozorg/templates/mozorg/home/home-m24.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@
{% include 'includes/protocol/footer/footer.html' %}
{% endwith %}
{% endblock %}

{% if switch('m24-hero-animation') %}
{% block js %}
{{ js_bundle('m24-animation') }}
{% endblock %}
{% endif %}
42 changes: 37 additions & 5 deletions bedrock/mozorg/templates/mozorg/home/includes/m24/hero.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,48 @@
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}

<div class="m24-t-dark m24-t-alt ">
<section class="m24-c-flag">
<div class="m24-c-flag-media">
<img src="{{ static('img/home/2024/hero-symbol-white.svg') }}" alt="" width="216" height="243">
</div>
<div class="m24-t-dark m24-t-alt" data-m24-hero-animation="{{ switch('m24-hero-animation') | lower }}">
<section class="m24-c-flag" data-animation-running="false">
<button class="m24-c-flag-button js-animation-button" aria-live="assertive">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went for assertive here as the text change might be confusing if not announced immediately after button click

<span class="m24-c-flag-button-pause"><img src="{{ static('img/m24/icon-pause.svg') }}" alt=""> <span class="m24-c-flag-button-text">{{ ftl('ui-pause-animation') }}</span></span>
<span class="m24-c-flag-button-play"><img src="{{ static('img/m24/icon-play.svg') }}" alt=""> <span class="m24-c-flag-button-text">{{ ftl('ui-play-animation') }}</span></span>
</button>
<div class="m24-c-flag-text">
<h1 class="m24-c-flag-title">{{ ftl('m24-home-welcome-to-mozilla') }}</h1>
<p class="m24-c-flag-subtitle">{{ ftl('m24-home-from-trustworthy-tech') }}</p>
<p class="m24-c-flag-cta"><a href="{{ url('mozorg.about.index') }}" class="m24-c-cta m24-t-lg" data-cta-text="Learn about us">{{ ftl('m24-home-learn-about-us') }}</a></p>
</div>
<div class="m24-c-flag-media">
<svg class="m24-c-flag-media-static" xmlns="http://www.w3.org/2000/svg" width="216" height="243" fill="none" viewBox="0 0 216 243"><path d="M93.573 29v20.734h72.565v5.351l-61.196 22.238v18.728l61.196 22.237v5.352H72.172v20.734h115.367v-37.788l-49.826-17.224v-5.349l49.826-17.222V29H93.573ZM29.034 214.6h23.743V29H29.034v185.6ZM72.172 71.136h21.401V49.734H72.172v21.402Z" /></svg>
<svg class="m24-c-flag-media-animation" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 176.26 200.19">
<defs>
<filter id="dilate" x="-10%" y="-10%" width="120%" height="120%">
<feMorphology operator="dilate" radius="0.3" in="SourceGraphic" result="dilated" />
</filter>
</defs>
<g class="wave">
<path shape-rendering="crispEdges" class="pole" d="M39.55,181.45h-20.77V19.06h20.77v162.4ZM56.52" />
<polygon shape-rendering="crispEdges" class="flag-five"
points="126.03 37.2 138.74 37.2 138.74 41.88 126.03 46.5 126.03 62.99 157.47 52.12 157.47 19.06 126.03 19.06 126.03 37.2" />
<polygon shape-rendering="crispEdges" class="flag-five"
points="126.03 101.87 126.03 120.01 157.47 120.01 157.47 86.94 126.03 76.08 126.03 92.56 138.74 97.18 138.74 101.87 126.03 101.87" />
<polygon shape-rendering="crispEdges" class="flag-four"
points="113.88 88.15 126.02 92.56 126.02 76.07 113.88 71.87 113.88 88.15" />
<rect shape-rendering="crispEdges" class="flag-four" x="113.88" y="101.87" width="12.15" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-four" x="113.88" y="19.06" width="12.15" height="18.14" />
<polygon shape-rendering="crispEdges" class="flag-four"
points="113.88 50.92 113.88 67.19 126.02 62.99 126.02 46.5 113.88 50.92" />
<polygon shape-rendering="crispEdges" class="flag-three"
points="113.88 67.19 113.88 50.92 85.2 61.34 85.2 77.73 113.88 88.15 113.88 71.87 113.87 71.87 113.87 67.19 113.88 67.19" />
<rect shape-rendering="crispEdges" class="flag-three" x="85.19" y="101.87" width="28.68" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-three" x="85.19" y="19.06" width="28.68" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-two" x="75.16" y="101.87" width="10.02" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-two" x="75.25" y="19.06" width="9.93" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-one" x="56.52" y="101.87" width="18.63" height="18.14" />
<rect shape-rendering="crispEdges" class="flag-one" x="56.52" y="37.2" width="18.73" height="18.73" />
</g>
</svg>
</div>
</section>
</div>

Expand Down
2 changes: 2 additions & 0 deletions l10n/en/ui.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ ui-show-all = Show All
ui-hide-all = Hide All
ui-learn-more = Learn more
ui-view = View
ui-pause-animation = Pause animation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise: Thanks for making these global.

ui-play-animation = Play animation

# An accessible label used to describe the purpose of a cross-promotional page element.
ui-promo-label = Promotion
229 changes: 220 additions & 9 deletions media/css/m24/flag.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

.m24-c-flag {
@include container;
padding-top: $spacer-2xl;
padding-top: $spacer-xl;
padding-bottom: $spacer-xl;
}

Expand All @@ -20,17 +20,81 @@

.m24-c-flag-subtitle {
font-size: $text-title-md;
stephaniehobson marked this conversation as resolved.
Show resolved Hide resolved
text-wrap: balance;
text-wrap-style: balance;
margin-bottom: $spacer-xl;
}

.m24-c-flag-cta {
margin-bottom: 0;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removes default p spacing

}

.m24-c-flag-media {
display: block;
margin-bottom: 16px;
--delay: 1s; // leave some space to read before introducing movement
--wave-h: 8px;

img {
svg {
transform: translateZ(0);
width: 100px;
height: auto;
fill: $m24-color-green; // zilla green
}
}

.m24-c-flag-button {
$font-size: 0.75;
all: unset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removed the focus ring. Can you add it back please? Ideally with the native focus ring . But if that is finiky any kind of outline would be a good addition.

background-color: $m24-color-dark-mid-gray;
color: $m24-color-white;
font-family: $primary-font;
font-size: calc(#{$font-size} * 1rem);
font-weight: 600;
line-height: $font-size;
padding: 8px;
cursor: pointer;
transition: background-color $fast;

&:hover,
&:focus {
background-color: $m24-color-black; // inverts to white in dark theme section
}

&:active {
background-color: $m24-color-dark-mid-gray;
}
}

.m24-c-flag-button-pause,
.m24-c-flag-button-play {
align-items: center;
display: flex;
gap: 8px;
}

.m24-c-flag-button-pause {
.m24-c-flag-button-text {
position: relative;
top: 0.0175rem; // flex alignment isn't totally centered, so we're manually adjusting
}
}

@media screen and (width < #{$screen-lg}) {
.m24-c-flag-cta {
margin-bottom: $spacer-xl;
}

.m24-c-flag-button {
border-radius: 50%;
display: block;
margin-bottom: $spacer-md;
margin-inline-start: auto;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logical properties have pretty good support now, so I decided to use them as enhancement here instead of bidi mixin

}

.m24-c-flag-button-text {
@include visually-hidden;
}

.m24-c-flag-media {
width: fit-content;
margin-inline-start: auto;
}
}

Expand All @@ -44,29 +108,36 @@
@media #{$mq-lg} {
.m24-c-flag {
@include grid;
grid-template-rows: [button-row-start] auto [button-row-end] auto;
padding-bottom: $spacer-2xl;
}

.m24-c-flag-button {
grid-column: 1 / -1;
grid-row: button-row;
justify-self: end;
}

.m24-c-flag-subtitle {
font-size: 24px;
}

.m24-c-flag-media {
grid-column: 10/12;
grid-row: 1/2;
grid-row-start: button-row-end;
display: flex;
place-content: center center;
margin-bottom: 0;

img {
svg {
width: 100%;
max-width: 216px;
}
}

.m24-c-flag-text {
grid-column: 2/9;
grid-row: 1/2
grid-row-start: button-row-end;
}

.m24-c-flag-cta {
Expand All @@ -86,3 +157,143 @@
.m24-c-products {
background-color: $m24-color-white;
}

// static fallback
.m24-c-flag-media-static {
display: none;
}

// When no JS or M24_HERO_ANIMATION switch is off
// - hide animation SVG and button
// - show static SVG
.no-js,
[data-m24-hero-animation="false"] {
.m24-c-flag-button {
visibility: hidden; // reserve space
}

.m24-c-flag-media-animation {
display: none;
}

.m24-c-flag-media-static {
display: block;
}
}

/*
Note from Inclusive Components, "Changing labels": https://inclusive-components.design/toggle-button/
As a rule of thumb, you should never change pressed state and label together.
If the label changes, the button has already changed state in a sense,
just not via explicit WAI-ARIA state management.
*/
[data-animation-running="false"] {
.m24-c-flag-button-pause {
display: none;
}

.flag-one,
.flag-two,
.flag-three,
.flag-four,
.flag-five {
animation-play-state: paused;
}
}

[data-animation-running="true"] {
.m24-c-flag-button-play {
display: none;
}

.flag-one,
.flag-two,
.flag-three,
.flag-four,
.flag-five {
animation-play-state: running;
}
}

/* Common Element Styles */
.flag,
.flag-one,
.flag-two,
.flag-three,
.flag-four,
.flag-five,
.pole,
.head,
.pole-one,
.pole-two,
.eye,
.mouth {
shape-rendering: crispEdges;
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: none;
}

/* Wave Animations Base */
.flag-one,
.flag-two,
.flag-three,
.flag-four,
.flag-five {
animation: 1s var(--delay) $bezier infinite;
will-change: transform;
filter: url("#dilate");
}

/* Flag Animation Names */
.flag-one { animation-name: flag-one; }
.flag-two { animation-name: flag-two; }
.flag-three { animation-name: flag-three; }
.flag-four { animation-name: flag-four; }
.flag-five { animation-name: flag-five; }


/* Flag Movement Keyframes */
@keyframes flag-one {
0%, 15% {
transform: translate3d(0, 0, 0);
animation-timing-function: ease-in;
}
16%, 40% { transform: translate3d(0, var(--wave-h), 0); }
41%, 65% { transform: translate3d(0, 0, 0); }
66%, 91% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
92%, 100% { transform: translate3d(0, 0, 0); }
}

@keyframes flag-two {
0%, 24% { transform: translate3d(0, 0, 0); }
25%, 49% { transform: translate3d(0, var(--wave-h), 0); }
50%, 74% { transform: translate3d(0, 0, 0); }
75%, 99% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
100% { transform: translate3d(0, 0, 0); }
}

@keyframes flag-three {
0%, 7% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
8%, 32% { transform: translate3d(0, 0, 0); }
33%, 57% { transform: translate3d(0, var(--wave-h), 0); }
58%, 82% { transform: translate3d(0, 0, 0); }
83%, 100% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
}

@keyframes flag-four {
0%, 15% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
16%, 49% { transform: translate3d(0, 0, 0); }
50%, 65% { transform: translate3d(0, var(--wave-h), 0); }
66%, 100% { transform: translate3d(0, 0, 0); }
}

@keyframes flag-five {
0%, 24% { transform: translate3d(0, calc(-1 * var(--wave-h)), 0); }
25%, 49% { transform: translate3d(0, 0, 0); }
50%, 74% { transform: translate3d(0, var(--wave-h), 0); }

75%, 100% {
transform: translate3d(0, 0, 0);
animation-timing-function: ease-out;
}
}
1 change: 0 additions & 1 deletion media/img/home/2024/hero-symbol-white.svg

This file was deleted.

1 change: 1 addition & 0 deletions media/img/m24/icon-pause.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions media/img/m24/icon-play.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions media/js/m24/animation-play-state.es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

const ANIMATION_RUNNING = 'data-animation-running';

function togglePlayState(e) {
const animationContainer = e.target.closest(`[${ANIMATION_RUNNING}]`);
if (animationContainer.getAttribute(ANIMATION_RUNNING) === 'true') {
animationContainer.setAttribute(ANIMATION_RUNNING, 'false');
} else {
animationContainer.setAttribute(ANIMATION_RUNNING, 'true');
}
}

function init() {
// play animations if motion is allowed
if (window.Mozilla.Utils.allowsMotion()) {
const animationContainers = document.querySelectorAll(
`[${ANIMATION_RUNNING}]`
);
animationContainers.forEach((container) =>
container.setAttribute(ANIMATION_RUNNING, 'true')
);
}

// play or pause animations on button click
const playStateButtons = document.querySelectorAll('.js-animation-button');
playStateButtons.forEach((button) =>
button.addEventListener('click', (e) => togglePlayState(e))
);
}

init();
Loading
Loading