Skip to content

Commit

Permalink
feat(ripple): Implement improved graceful degradation for ripple
Browse files Browse the repository at this point in the history
Resolves #189
  • Loading branch information
cristobalchao@google.com committed Feb 10, 2017
1 parent c25d387 commit fd06f07
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 147 deletions.
76 changes: 75 additions & 1 deletion demos/button.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ <h1>MDC WEB BUTTON</h1>
Div
</div>
</fieldset>
<fieldset>
<legend>Graceful degraded buttons</legend>
<button class="mdc-button" no-js>
Default
</button>
<button class="mdc-button mdc-button--raised" no-js>
Raised
</button>
<button class="mdc-button mdc-button--dense" no-js>
Dense Default
</button>
<button class="mdc-button mdc-button--raised mdc-button--dense" no-js>
Dense Raised
</button>
<button class="mdc-button mdc-button--compact" no-js>
Compact
</button>
<button class="mdc-button mdc-button--raised mdc-button--compact" no-js>
Compact Raised
</button>
<button class="mdc-button mdc-button--primary" no-js>
Default with Primary
</button>
<button class="mdc-button mdc-button--raised mdc-button--primary" no-js>
Raised with Primary
</button>
<button class="mdc-button mdc-button--accent" no-js>
Default with Accent
</button>
<button class="mdc-button mdc-button--raised mdc-button--accent" no-js>
Raised with Accent
</button>
<div class="mdc-button mdc-button--raised" tabindex="0" role="button" no-js>
Div
</div>
</fieldset>
<fieldset>
<legend>Links with Button Style</legend>
<a href="/button.html" class="mdc-button">
Expand Down Expand Up @@ -183,6 +219,42 @@ <h2>Dark theme</h2>
Div
</div>
</fieldset>
<fieldset>
<legend>Graceful degraded buttons</legend>
<button class="mdc-button" no-js>
Default
</button>
<button class="mdc-button mdc-button--raised" no-js>
Raised
</button>
<button class="mdc-button mdc-button--dense" no-js>
Dense Default
</button>
<button class="mdc-button mdc-button--raised mdc-button--dense" no-js>
Dense Raised
</button>
<button class="mdc-button mdc-button--compact" no-js>
Compact
</button>
<button class="mdc-button mdc-button--raised mdc-button--compact" no-js>
Compact Raised
</button>
<button class="mdc-button mdc-button--primary" no-js>
Default with Primary
</button>
<button class="mdc-button mdc-button--raised mdc-button--primary" no-js>
Raised with Primary
</button>
<button class="mdc-button mdc-button--accent" no-js>
Default with Accent
</button>
<button class="mdc-button mdc-button--raised mdc-button--accent" no-js>
Raised with Accent
</button>
<div class="mdc-button mdc-button--raised" tabindex="0" role="button" no-js>
Div
</div>
</fieldset>
<fieldset disabled>
<legend>Disabled Buttons</legend>
<button class="mdc-button">
Expand Down Expand Up @@ -238,7 +310,9 @@ <h2>Dark theme</h2>
function init() {
var btns = document.querySelectorAll('.mdc-button');
for (var i = 0, btn; btn = btns[i]; i++) {
mdc.ripple.MDCRipple.attachTo(btn);
if (!btn.hasAttribute('no-js')) {
mdc.ripple.MDCRipple.attachTo(btn);
}
}
}
})();
Expand Down
87 changes: 68 additions & 19 deletions demos/ripple.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@
}

section {
margin: 48px;
align-items: center;
display: flex;

}

section > div {
margin: 48px 0;
width: 400px;
}

body {
Expand Down Expand Up @@ -92,41 +99,83 @@
<main>
<h1>MDC Ripple</h1>
<section>
<h2>Bounded</h2>
<div class="mdc-ripple-surface demo-surface mdc-elevation--z2" tabindex="0">
Interact with me!
<div>
<h2>Bounded</h2>
<div class="mdc-ripple-surface demo-surface mdc-elevation--z2" tabindex="0">
Interact with me!
</div>
</div>
<div>
<h2>Bounded - Graceful degraded</h2>
<div class="mdc-ripple-surface demo-surface mdc-elevation--z2" no-js tabindex="0">
Interact with me!
</div>
</div>
</section>
<section>
<h2>Unbounded</h2>
<div class="mdc-ripple-surface demo-surface material-icons" data-mdc-ripple-is-unbounded
aria-label="Favorite" tabindex="0">
favorite
<div>
<h2>Unbounded</h2>
<div class="mdc-ripple-surface demo-surface material-icons" data-mdc-ripple-is-unbounded
aria-label="Favorite" tabindex="0">
favorite
</div>
</div>
<div>
<h2>Unbounded - Graceful degraded</h2>
<div class="mdc-ripple-surface demo-surface material-icons" data-mdc-ripple-is-unbounded
aria-label="Favorite" no-js tabindex="0">
favorite
</div>
</div>
</section>
<section>
<h2>Theme Styles</h2>
<div
class="mdc-ripple-surface mdc-ripple-surface--primary
mdc-theme--primary demo-surface mdc-elevation--z2" tabindex="0">
Primary
<div>
<h2>Theme Styles</h2>
<div
class="mdc-ripple-surface mdc-ripple-surface--primary
mdc-theme--primary demo-surface mdc-elevation--z2" tabindex="0">
Primary
</div>
<div
class="mdc-ripple-surface mdc-ripple-surface--accent
mdc-theme--accent demo-surface mdc-elevation--z2" tabindex="0">
Accent
</div>
</div>
<div
class="mdc-ripple-surface mdc-ripple-surface--accent
mdc-theme--accent demo-surface mdc-elevation--z2" tabindex="0">
Accent
<div>
<h2>Theme Styles - Graceful degraded</h2>
<div
class="mdc-ripple-surface mdc-ripple-surface--primary
mdc-theme--primary demo-surface mdc-elevation--z2" no-js tabindex="0">
Primary
</div>
<div
class="mdc-ripple-surface mdc-ripple-surface--accent
mdc-theme--accent demo-surface mdc-elevation--z2" no-js tabindex="0">
Accent
</div>
</div>

</section>
<section>
<h2>Applied to <code>&lt;button&gt; element</h2>
<div>
<h2>Applied to <code>&lt;button&gt; element</h2>
<button type="button" class="mdc-ripple-surface mdc-elevation--z2 demo-surface">button</button>
</div>
<div>
<h2>Applied to <code>&lt;button&gt; element - Graceful degraded</h2>
<button type="button" class="mdc-ripple-surface mdc-elevation--z2 demo-surface" no-js>button</button>
</div>

</section>
</main>
<script src="assets/material-components-web.js" charset="utf-8"></script>
<script>
(function(global) {
[].forEach.call(document.querySelectorAll('.mdc-ripple-surface'), function(surface) {
mdc.ripple.MDCRipple.attachTo(surface);
if (!surface.hasAttribute('no-js')) {
mdc.ripple.MDCRipple.attachTo(surface);
}
});
})(this);
</script>
Expand Down
92 changes: 33 additions & 59 deletions packages/mdc-button/mdc-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,39 @@
@import "@material/typography/mixins";

// postcss-bem-linter: define button

.mdc-button {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before"));
@include mdc-ripple-fg((pseudo: "::after"));

overflow: hidden;

@include mdc-theme-dark(".mdc-button", true) {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before", base-color: white, opacity: .14));
@include mdc-ripple-fg((pseudo: "::after", base-color: white, opacity: .14));
}

@each $theme-style in (primary, accent) {
&.mdc-button--#{$theme-style} {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before", theme-style: $theme-style, opacity: .12));
@include mdc-ripple-fg((pseudo: "::after", theme-style: $theme-style, opacity: .12));
}
}
}

.mdc-button--raised {
@each $theme-style in (primary, accent) {
&.mdc-button--#{$theme-style} {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before", base-color: white, opacity: .14));
@include mdc-ripple-fg((pseudo: "::after", base-color: white, opacity: .14));
}
}
}

.mdc-button {
@include mdc-typography(body2);
@include mdc-theme-prop(color, text-primary-on-light);
Expand Down Expand Up @@ -54,37 +87,6 @@
}

// postcss-bem-linter: ignore
&::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: mdc-animation-exit(opacity, 120ms);
border-radius: inherit;
background: currentColor;
content: "";
opacity: 0;
}

&:focus::before {
transition: mdc-animation-enter(opacity, 120ms);
opacity: .12;
}

&:active::before {
transition: mdc-animation-enter(opacity, 120ms);

// Slightly darker value for visual distinction.
// This allows a full base that has distinct modes.
// Progressive enhancement with ripples will provide complete button spec alignment.
opacity: .18;
}

&:focus:active::before {
transition-timing-function: $mdc-animation-fast-out-slow-in-timing-function;
}

&:active {
outline: none;
}
Expand Down Expand Up @@ -196,31 +198,3 @@

// postcss-bem-linter: end

.mdc-button.mdc-ripple-upgraded {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before"));
@include mdc-ripple-fg((pseudo: "::after"));

overflow: hidden;

@include mdc-theme-dark(".mdc-button", true) {
@include mdc-ripple-bg((pseudo: "::before", base-color: white, opacity: .14));
@include mdc-ripple-fg((pseudo: "::after", base-color: white, opacity: .14));
}

@each $theme-style in (primary, accent) {
&.mdc-button--#{$theme-style} {
@include mdc-ripple-bg((pseudo: "::before", theme-style: $theme-style, opacity: .12));
@include mdc-ripple-fg((pseudo: "::after", theme-style: $theme-style, opacity: .12));
}
}
}

.mdc-button--raised.mdc-ripple-upgraded {
@each $theme-style in (primary, accent) {
&.mdc-button--#{$theme-style} {
@include mdc-ripple-bg((pseudo: "::before", base-color: white, opacity: .14));
@include mdc-ripple-fg((pseudo: "::after", base-color: white, opacity: .14));
}
}
}
35 changes: 7 additions & 28 deletions packages/mdc-ripple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ to provide components (or any element at all) with a
material "ink ripple" interaction effect. It is designed to be efficient, un-invasive, and usable
without adding any extra DOM to your elements.

and includes a gracefully degraded version that can be used
in conjunction with the browser's native element

### An aside regarding browser support

In order to function correctly, MDC Ripple requires a _browser_ implementation of [CSS Variables](https://www.w3.org/TR/css-variables/). MDC Ripple uses custom properties to dynamically position pseudo elements, which allows us to not need any extra DOM for this effect.
Expand All @@ -39,8 +42,6 @@ Because we rely on scoped, dynamic CSS variables, static pre-processors such as
[Most modern browsers](http://caniuse.com/#feat=css-variables) support CSS variables, so MDC ripple will work just fine. In other cases, MDC ripple will _still work_ if you include it in your codebase. It will simply check if CSS variables are supported upon initialization and if they aren't, gracefully exit. The only exception to this rule is Safari, which does support CSS variables
but unfortunately ripples are disabled for (see [below](#caveat-safari) for an explanation).

Given this, it is important that you _provide gracefully degraded interaction states_ for browsers in which the ripple is not supported. We do this for all of our components.


## Installation

Expand Down Expand Up @@ -74,41 +75,17 @@ use [mdc-elevation](https://github.com/material-components/material-components-w
text-align: center;
/* Indicate to user element is interactive. */
cursor: pointer;


/* Use the surface's ::before pseudo-element as a basic interaction indicator */

&::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
background-color: black;
transition: opacity 110ms ease;
will-change: opacity;
}

&:active::before {
opacity: .18;
}

&:focus::before {
opacity: .06;
}
}
```

#### Adding the ripple Sass

When a ripple is successfully initialized on an element, it dynamically adds a `mdc-ripple-upgraded` class to that element. Therefore, to add a ripple to our surface, first we include the proper Sass mixins within our surface's styles when it contains this class. We also add a few additional properties that ensure the ripple's UX is correct.
To add a ripple to our surface, first we include the proper Sass mixins within our surface's styles when it contains this class. We also add a few additional properties that ensure the ripple's UX is correct.

```scss
@import "@material/elevation/mixins";
@import "@material/ripple/mixins";

.surface.mdc-ripple-upgraded {
.surface {
@include mdc-ripple-base;
@include mdc-ripple-bg((pseudo: "::before"));
@include mdc-ripple-fg((pseudo: "::after"));
Expand All @@ -121,6 +98,8 @@ When a ripple is successfully initialized on an element, it dynamically adds a `

This code sets up `.surface` with the correct css variables as well as `will-change` properties to support the ripple. It then dynamically generates the correct selectors such that the surface's `::before` element functions as a background ripple, and the surface's `::after` element functions as a foreground ripple.

When a ripple is successfully initialized on an element, it dynamically adds a `mdc-ripple-upgraded` class to that element. If ripple is not initialized but Sass misins are included within our surface, the ripple would be on a graceful degraded state.

##### The full Sass API

Both `mdc-ripple-bg` and `mdc-ripple-fg` take an `$config` map as an optional
Expand Down
Loading

0 comments on commit fd06f07

Please sign in to comment.