Slide 1

Slide 1 text

Dirty Tricks From Dark Corners Of Front-End Vitaly Friedman August 25th, 2016 • Reykjavik, Iceland

Slide 2

Slide 2 text

Vitaly Friedman, editor-in-chief
 and co-founder of SmashingMag

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Front-End Challenges

Slide 5

Slide 5 text

“What if you want to nest one link inside another? E.g. in sidenotes, footnotes or articles, when you want the entire excerpt to be linked, but the excerpt could potentially also contain links which you can’t strip out from the markup? 
 — Roman Komarov

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

• HTML:
 When the crisis was over,
 Mr. Jones
 left the region immediately. • Browser parser reads it as:
 When the crisis was over,Mr. Jones
 left the region immediately.

Slide 8

Slide 8 text

• Browser parser reads it as:
 When the crisis was over,Mr. Jones
 left the region immediately. • HTML:
 When the crisis was over,
 Mr. Jones
 left the region immediately.

Slide 9

Slide 9 text

• Browser parser reads it as:
 When the crisis was over,Mr. Jonesleft the region immediately. • HTML:
 When the crisis was over,
 Mr. Jones
 left the region immediately.

Slide 10

Slide 10 text

• Browser parser reads it as:
 When the crisis was over,Mr. Jonesleft the region immediately. • HTML:
 When the crisis was over,
 Mr. Jones
 left the region immediately.

Slide 11

Slide 11 text

• Browser parser reads it as:
 When the crisis was over,Mr. Jonesleft the region immediately. • HTML:
 When the crisis was over,
 Mr. Jones
 left the region immediately. • Works well in modern browsers:
 IE 9+, Firefox 4+, Opera 9+, Safari 5.1+, Chrome 14+.
 For old IE, we can use Cond. comments inside .

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

SVG Embedding • , background: url(image.svg); block access to SVG paths via CSS. • With “inline” SVG or Data URI encoding we can style SVG via CSS and avoid one HTTP-request. 
 


Slide 16

Slide 16 text

SVG Embedding • With “inline” SVG or Data URI encoding we can style SVG via CSS and avoid one HTTP-request. • Alternative: using SVG as an avoids
 caching issues with CSS styling within SVG.
 
 
 
 
 
 
 …

Slide 17

Slide 17 text

“By default, broken images look pretty unspectacular. Is there any way to improve the experience by changing the styling if images are actually broken?

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

The element is a replaced element. This is an element “whose appearance and dimensions are defined by an external resource. Pseudo-elements typically shouldn’t work with it.

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

“To achieve fluid typography, we can combine the calc( ) function in CSS with viewport units (vw/vh/vmin/ vmax). But what if you want to apply a modular scale to font sizes?

Slide 28

Slide 28 text

We can get perfectly fluid type with
 html { font-size: calc(1em + 1vw); } but it gives us little control over the rate at which viewport units change. Media queries? Well, with them usually there is an annoying “visual” jump between fixed and fluid values. 
 — Mike Riethmuller

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

…E.g. if we wanted to choose a font- size of 16px at a screen resolution of 400px and then transition to 24px at a resolution of 800px, we couldn’t do it without a breakpoint. 
 — Mike Riethmuller

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

You choose the min and max font- size and the screen sizes, over which the font should scale and plug them into the equation. You can use any unit type including ems, rems or px. 
 — Mike Riethmuller

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

“How do you make sure that in a multi-column table, both a row and a column are highlighted on hover and on tap? Highlighting the current row is easy, but what about the column? 
 — Matt Walton

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

“We create tall pseudo elements on ’s with a negative top-value of half of that value. Then we hide these pseudo elements with oveflow: hidden, and use negative z-index to keep it below the content. Then we make all cells focusable and focus them on touchstart. 
 — @simurai

Slide 46

Slide 46 text

• CSS:
 table { overflow: hidden; }
 td, th { position: relative; }
 tr:hover { background-color: #ffa; }
 td:hover::after { content: "";
 position: absolute;
 width: 100%;
 height: 10000px;
 left: 0;
 top: -5000px;
 background-color: currentColor;
 z-index: -1;
 }

Slide 47

Slide 47 text

• CSS:
 table { overflow: hidden; }
 tr:hover { background-color: #ffa; }
 td:hover::after,
 th:hover::after { content: "";
 position: absolute;
 width: 100%;
 height: 10000px;
 left: 0;
 top: -5000px;
 background-color: currentColor;
 z-index: -1;
 }

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

“Email clients, primarily Gmail, don’t support media queries. To build responsive email layouts, we have to use table-layouts. But is there a better way?

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

/* “Desktop” width = 600px = 300*2 */ 
 
 ...
 ...
 
 
 • Content Stacking

Slide 55

Slide 55 text

@media only screen and (max-width: 600px) {
 table, tr, td {
 display: block; /* table-cell -> block */
 width: 100%;
 }
 }
 • Content Stacking

Slide 56

Slide 56 text

• Column Switching /* “Desktop” width = 600px = 300*2 */ 
 
 ...
 ...
 
 


Slide 57

Slide 57 text

@media only screen and (max-width: 500px) {
 table, tr, td {
 display: block; /* table-cell -> block */
 width: 100%;
 }
 
 td[class=main-col] { display: table-header-group; }
 td[class=sub-col] { display: table-footer-group; }
 }
 • Column Switching

Slide 58

Slide 58 text

/* “Desktop” width = 600px */ 
 
 ...
 

...
...

 
 
 • Image Shifter

Slide 59

Slide 59 text

@media only screen and (max-width: 500px) {
 table, tr, td { display: block; }
 td[class=image] { float: left; }
 .description { clear: both; }
 }
 • Image Shifter

Slide 60

Slide 60 text

• Order and Re-order /* Nested tables, oh my... */ 
 Header
 Navigation
 Content
 Footer
 /table>

Slide 61

Slide 61 text

@media only screen and (max-width: 500px) {
 table[class=wrapper] { display: table; }
 table[class=header] { display: table-caption; }
 table[class=nav] { display: block; }
 table[class=content] { display: table-header-group; }
 table[class=footer] { display: table-footer-group; }
 }
 • Order and Re-order

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

HTTP/1.1 Deployment Strategy • CSS:
 .box {
 width: 320px;
 min-width: 480px;
 max-width: 160px;
 } If the width value is greater than the max-width value, max-width wins.

Slide 67

Slide 67 text

HTTP/1.1 Deployment Strategy • CSS:
 .box {
 width: 320px;
 min-width: 480px;
 max-width: 160px;
 } If the min-width value is greater than the width or max-width values, then min-width wins.

Slide 68

Slide 68 text

HTTP/1.1 Deployment Strategy • CSS:
 .box {
 display: inline-block;
 min-width: 50%; // basically 2-col-desktop version
 max-width: 100%; // basically 1-col-mobile version
 width: calc((480px - 100%) * 480);
 /* 480px = the breakpoint, 100% = width of the parent
 Goal: create a value bigger than our max-width or smaller than our min-width, so that either one of those property is applied instead. */
 } Let’s build a 2-col-layout that stacks and grows below 480px.
 No media queries allowed.

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

“You want to add a background to inline text for headings, but the text should be padded along both the left and right edge of each line. The left and right padding will only apply to the very first and very last line.

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

The box-decoration-break in CSS specifies element’s appearance if the box for the element is fragmented, i.e when an inline box wraps onto multiple lines, or when a block spans more than one column inside a column layout container.

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

“Images make up a large portion of bandwidth payload. Is there any way to optimize images beyond good ol’ image optimization? What if a hero image has to render fast, e.g. on landing pages? 
 — Tobias Baldauf

Slide 93

Slide 93 text

• The original photo has 1600px width, 971 Kb. Quality 60 brings the size down to 213 Kb.

Slide 94

Slide 94 text

• Blurring unimportant parts of the photo brings the size down to 147 Kb.

Slide 95

Slide 95 text

Sequential JPEG Progressive JPEG Images taken from http://www.pixelstech.net/article/1374757887-Use-progressive-JPEG-to-improve-user-experience 13 / 44

Slide 96

Slide 96 text

Scans 14 / 44

Slide 97

Slide 97 text

Default Scan Levels Thanks to Frédéric Kayser for creating 'jsk': http://encode.ru/threads/1800-JSK-JPEG-Scan-Killer-progressive-JPEG-explained-in-slowmo 15 / 44

Slide 98

Slide 98 text

16 / 44

Slide 99

Slide 99 text

17 / 44

Slide 100

Slide 100 text

18 / 44

Slide 101

Slide 101 text

1st Scan Layer Has Small Byte Size Ships Fast & Shows Soon 19 / 44

Slide 102

Slide 102 text

31 / 44

Slide 103

Slide 103 text

1 32 / 44

Slide 104

Slide 104 text

2 33 / 44

Slide 105

Slide 105 text

3 34 / 44

Slide 106

Slide 106 text

4 35 / 44

Slide 107

Slide 107 text

5 36 / 44

Slide 108

Slide 108 text

37 / 44

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

“By default, tables are quite unpredictable and spongy, and if you don’t know how lengthy the content inside cells will be, some columns can be unpredictably wide, destroying the layout. What to do? 
 — Louis Lazaris

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

“With table-layout: fixed; the layout is fixed based on the first row. Set the width of those, and the rest of the table follows. 
 — Chris Coyier

Slide 116

Slide 116 text

No content

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

“Whenever the content is dynamically injected into the DOM or when “above-the-fold” CSS is used or font changes, users see content jumping around. That’s particularly annoying on small screens. Can we fix it?

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

If we know the expected height of the block, we can use min-height to “reserve” space for it, or calculate it with JavaScript on window early on and write styles dynamically.

Slide 122

Slide 122 text

Alternatively, we could use a smooth transition from the initial (fixed) height to the final (fixed) height. Downside: transitions don’t work on min-height.

Slide 123

Slide 123 text

No content

Slide 124

Slide 124 text

• CSS:
 .ad-wrapper {
 height: 0;
 overflow: hidden;
 transition: height 0.8s ease-out;
 }
 
 .ad-wrapper.loaded {
 height: 400px;
 }

Slide 125

Slide 125 text

No content

Slide 126

Slide 126 text

“What’s the deal with emoji? Can we style them with CSS, or change them with JavaScript? Or even better, can they be an alternative to SVG and icon fonts?

Slide 127

Slide 127 text

No content

Slide 128

Slide 128 text

Clockwise Rightwards and Leftwards Open Circle Arrows With Circled One Overlay
 (also known as U+1F502, 🔂 or \u1f502).

Slide 129

Slide 129 text

Person Raising Both Hands in Celebration (also known as Festivus Miracle Emoji,
 U+1F64C, f64c; or \u1f64c).

Slide 130

Slide 130 text

%

Slide 131

Slide 131 text

No content

Slide 132

Slide 132 text

No content

Slide 133

Slide 133 text

No content

Slide 134

Slide 134 text

No content

Slide 135

Slide 135 text

No content

Slide 136

Slide 136 text

No content

Slide 137

Slide 137 text

No content

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

Emoji are coloured glyphs added into Unicode 6.0 in 2010. They are depicted in the spec, but the exact appearance isn’t defined and varies between fonts, just like normal typefaces display letters differently.

Slide 140

Slide 140 text

No content

Slide 141

Slide 141 text

No content

Slide 142

Slide 142 text

No content

Slide 143

Slide 143 text

No content

Slide 144

Slide 144 text

Because emoji are Unicode code points, we can create a font with the emoji that we need in our interface and override platform-specific designs to avoid inconsistencies.

Slide 145

Slide 145 text

No content

Slide 146

Slide 146 text

Internally strings are represented
 in UTF-16, so each code point can be represented by one or more 16-bit code units. Some emojis use only 1 code unit, others 2 and more.

Slide 147

Slide 147 text

Not all emoji are created equal.
 They can be modified with emoji modifiers, so some are surrogates which is why sometimes icons are rendered incorrectly.

Slide 148

Slide 148 text

No content

Slide 149

Slide 149 text

( ) *

Slide 150

Slide 150 text

• HTML:


%

Slide 151

Slide 151 text

• The browser will: — Look up the glyph in the Sentinel font,
 — If it can’t find the glyph, it will fall back to the fallback font,
 — In this case, fallback is sans-serif (Helvetica/Arial),
 — The fallback doesn’t have the glyph either,
 — Browser will try to figure out the glyph type,
 — Eventually it will look up in a locally installed Emoji font
 (e.g. AppleColorEmoji),
 — The browser will render the icon. • HTML:


%

Slide 152

Slide 152 text

No content

Slide 153

Slide 153 text

No content

Slide 154

Slide 154 text

No content

Slide 155

Slide 155 text

No content

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

No content

Slide 158

Slide 158 text

No content

Slide 159

Slide 159 text

No content

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

No content

Slide 162

Slide 162 text

“So you’re building a responsive multi-lingual website that aims to support over 30 languages. How do you architect a system to support this kind of complexity?

Slide 163

Slide 163 text

No content

Slide 164

Slide 164 text

The crucial asset of longevity is building “neutral”, configurable components which can be easily extended and adjusted.

Slide 165

Slide 165 text

// english.json
 {
 serviceName: 'english';
 language: 'en';
 textDirection: 'ltr';
 socialMediaButtons: ['twitter', 'facebook', 'reddit'];
 }
 
 // russian.json
 {
 serviceName: 'russian';
 language: 'ru';
 textDirection: 'ltr';
 textLength: 'verbose';
 socialMediaButtons: ['twitter', 'facebook', 'vk'];
 }

Slide 166

Slide 166 text

config/english.json
 /russian.json 
 css/english.css
 /russian.css
 
 sass/english.scss
 /russian.scss
 /mixins/_textDirection.scss
 /mixins/_textLength.scss
 /mixins/_socialMediaButtons.scss
 
 index.en.html
 index.ru.html

Slide 167

Slide 167 text

// english.scss
 $english = true;
 $script = 'latin';
 
 // russian.scss
 $russian = true;
 $script = 'cyrillic';
 
 @if $russian {
 // apply styling only to Russian version
 } With a templating language, we can then plug data
 from config files and hence customize HTML output
 for every language.

Slide 168

Slide 168 text

// english.scss
 $english = true;
 $script = 'latin';
 $direction = 'left';
 @include(mixins/directions);
 @include(mainstyles);
 
 // arabic.scss
 $arabic = true;
 $script = 'arabic';
 $direction = 'right';
 @include(mixins/directions);
 @include(mainstyles);
 
 @if $arabic {
 // apply styling only to Arabic version
 }

Slide 169

Slide 169 text

// directions.scss
 $margin-left: margin-left;
 if $direction == 'right' {
 $margin-left: margin-right;
 }
 
 $padding-left: padding-left;
 if $direction == 'right' {
 $padding-left: padding-right;
 }
 
 $left: left;
 if $direction == 'right' {
 $left: right;
 }

Slide 170

Slide 170 text

// directions.scss
 $margin-left: margin-left;
 if $direction == 'right' {
 $margin-left: margin-right;
 }
 
 $padding-left: padding-left;
 if $direction == 'right' {
 $padding-left: padding-right;
 }
 
 $left: left;
 if $direction == 'right' {
 $left: right;
 } $margin-right: margin-right;
 if $direction == 'right' {
 $margin-right: margin-left;
 } $padding-right: padding-right;
 if $direction == 'right' {
 $padding-right: padding-left;
 } $right: right;
 if $direction == 'right' {
 $right: left;
 }

Slide 171

Slide 171 text

// global.scss
 .nav-element {
 #{$margin-left}: 10px;
 #{$padding-right}: 10px;
 #{$left}: 10px;
 }
 
 // english.css
 .nav-element {
 margin-left: 10px;
 padding-right: 10px;
 left: 10px;
 }
 
 // arabic.css
 .nav-element {
 margin-right: 10px;
 padding-left: 10px;
 right: 10px;
 }
 .nav-element {
 float: flip(left, right);
 padding: flip(10px 10px 0 0,
 10px 0 0 10px);
 line-height: get-script-value
 (latin 1.3, arabic 1.6);
 }

Slide 172

Slide 172 text

// global.scss
 .nav-element {
 float: flip(left, right);
 padding: flip(10px 10px 0 0, 10px 0 0 10px);
 line-height: get-script-value(latin 1.3, arabic 1.6);
 }
 
 // english.css
 .nav-element {
 float: left;
 padding: 10px 10px 0 0;
 line-height: 1.3em;
 }
 
 // arabic.css
 .nav-element {
 float: right;
 padding: 10px 0 0 10px;
 line-height: 1.6em;
 }


Slide 173

Slide 173 text

No content

Slide 174

Slide 174 text

No content

Slide 175

Slide 175 text

No content

Slide 176

Slide 176 text

No content

Slide 177

Slide 177 text

No content

Slide 178

Slide 178 text

Sometimes web fonts might be out of question, so consider generating full page screenshots and sending a mix of HTML + images to the users.

Slide 179

Slide 179 text

No content

Slide 180

Slide 180 text

“What if you want to use a full- width element in a fixed-width container? E.g. when you want some content to extend beyond the boundaries of the container? 
 — Tyler Sticka

Slide 181

Slide 181 text

No content

Slide 182

Slide 182 text

• HTML:


...

...

• CSS:
 .u—containProse {
 margin: 0 auto;
 max-width: 40em;
 }

Slide 183

Slide 183 text

• HTML:


...


 
 ...
 


...


 • CSS:
 .u—containProse {
 margin: 0 auto;
 max-width: 40em;
 }

Slide 184

Slide 184 text

To release our child element from its container, we need to know how much space there is between the container edge and the viewport edge.

Slide 185

Slide 185 text

What’s this space exactly? Well, it’s half the viewport width minus half the container width. calc() to the rescue!

Slide 186

Slide 186 text

• HTML:


...

...

• CSS:
 .u—release {
 margin-left: calc(-50vw + 50%);
 margin-right: calc(-50vw + 50%);
 }

Slide 187

Slide 187 text

No content

Slide 188

Slide 188 text

When the height or width of the initial containing block is changed, they are scaled accordingly. Note that the initial containing block’s size is affected by the presence of scrollbars on the viewport.

Slide 189

Slide 189 text

• HTML:


...

...

• CSS:
 .u—release {
 margin-left: calc(-50vw + 50%);
 margin-right: calc(-50vw + 50%);
 }

Slide 190

Slide 190 text

• HTML:


...

...

• CSS:
 .u—release {
 margin-left: calc(-50vw + 50%);
 margin-right: calc(-50vw + 50%);
 } html, body {
 overflow-x: hidden;
 }

Slide 191

Slide 191 text

No content

Slide 192

Slide 192 text

• CSS:
 .u—release {
 width: 100vw;
 position: relative;
 left: 50%;
 right: 50%;
 margin-left: -50vw;
 margin-right: -50vw;
 } We push the container to the exact middle of the browser window with left: 50%, then pull it back to the left edge with -50vw margin
 (h/t Sven Wolfermann).

Slide 193

Slide 193 text

No content

Slide 194

Slide 194 text

“What if you want to build fluid horizontal lines around centered content for an art-directed article? How exactly would you build it? 
 — Jack Brewer

Slide 195

Slide 195 text

No content

Slide 196

Slide 196 text

• CSS:
 .has-lines {
 display: flex;
 justify-content: center; // horizontal alignment
 align-items: center; // replace stretch / v. alignment
 }

Slide 197

Slide 197 text

• CSS:
 .has-lines {
 display: flex;
 justify-content: center; // horizontal alignment
 align-items: center; // replace stretch / v. alignment
 } .has-lines:before, .has-lines:after {
 content: '';
 display: inline-block;
 vertical-align: middle;
 flex-grow: 1; // take all the space you can
 height: 1px;
 background: #ccc;
 min-width: 20px;
 }

Slide 198

Slide 198 text

• CSS:
 .has-lines {
 display: flex;
 justify-content: center; // horizontal alignment
 align-items: center; // replace stretch / v. alignment
 } .has-lines:before, .has-lines:after {
 content: '';
 display: inline-block;
 vertical-align: middle;
 flex-grow: 1; // take all the space you can
 height: 1px;
 background: #ccc;
 min-width: 20px;
 } .has-lines:before { margin-right: 20px; }
 .has-lines:after { margin-left: 20px; }

Slide 199

Slide 199 text

No content

Slide 200

Slide 200 text

“So you want to implement a baseline rhythm in CSS. Insert two differently formatted elements next to each other and they’ll seem out of phase. How do we bring them under control? 
 — Jan Dudek

Slide 201

Slide 201 text

No content

Slide 202

Slide 202 text

Often we define a common line height value (or its multiple) that’s used for all elements, including their paddings and margins, occasionally taking border widths into the equation.

Slide 203

Slide 203 text

What if we align the baseline instead? So that all type—regardless of its size —lies on the same grid line? We just need to calculate the offset and then shift the content by that offset.

Slide 204

Slide 204 text

No content

Slide 205

Slide 205 text

By default, browsers center the cap height between grid lines (the height of a capital letter above the baseline). So we shift it by half the difference between line height and cap height.

Slide 206

Slide 206 text

To determine the cap height, we
 fiddle with offset values until the
 type is properly aligned with the grid.

Slide 207

Slide 207 text

$font-stacks: (
 s: $font-stack-text,
 m: $font-stack-text,
 l: $font-stack-display,
 xl: $font-stack-display
 ); • vertical-rhythm.scss: $line-height: 24px; $font-sizes: (s: 13px, m: 15px, l: 19px, xl: 27px);
 $cap-heights: (s: 0.8, m: 0.8, l: 0.68, xl: 0.68);

Slide 208

Slide 208 text

$font-stacks: (
 s: $font-stack-text,
 m: $font-stack-text,
 l: $font-stack-display,
 xl: $font-stack-display
 ); @function rhythm-shift($size-name) {
 $font-size: map-get($font-sizes, $size-name);
 $cap-height: map-get($cap-heights, $size-name);
 $offset: ($line-height - $cap-height * $font-size) / 2;
 return round($offset);
 } $line-height: 24px; $font-sizes: (s: 13px, m: 15px, l: 19px, xl: 27px);
 $cap-heights: (s: 0.8, m: 0.8, l: 0.68, xl: 0.68);

Slide 209

Slide 209 text

Now we just need to apply the offset, and do so reliably. We can combine positive top margin and negative bottom margin to make it work.

Slide 210

Slide 210 text

.rhythm-m {
 margin-top: $offset;
 margin-bottom: -1 * $offset;
 } $offset: rhythm-shift(m);

Slide 211

Slide 211 text

• Collapsing works differently with positive and negative margins: • Two positive margins
 The bigger one wins. • Two negative margins
 The lower (i.e. the more negative) wins. • One positive, one negative margin
 The margins sum up.

Slide 212

Slide 212 text

If an element doesn’t have a border nor padding, and its first child has a margin, that margin will flow out of the parent. Use overflow: hidden.

Slide 213

Slide 213 text

No content

Slide 214

Slide 214 text

No content

Slide 215

Slide 215 text

“What’s the best way to encode and compress a 1×1px image? It could be useful as a placeholder or default image, for example. 
 — Jon Sneyers

Slide 216

Slide 216 text

Slide 217

Slide 217 text

Uncompressed pixel is just one bit to four bytes – depending on how we define it: as black & white (1 bit), grayscale (1 byte), grayscale + alpha
 (2 bytes), RGB (3 bytes), or RGBA
 (4 bytes).

Slide 218

Slide 218 text

Every image format specifies how to interpret the data: the width and height of the image, and the number of bits or bytes per pixel (headers).

Slide 219

Slide 219 text

• Image formats contain headers with some meta information: • Magic number
 A fixed identifier, e.g. GIF87A/GIF89a, JFIF, Exif, PNG. • Decoding details
 Color profiles, orientation, gamma, or dots-per-pixel. • Arbitrary metadata
 Timestamps, copyright notices, or GPS coordinates. • “Overhead” stuff
 Markers and checksums or paddings for robustness.

Slide 220

Slide 220 text

No content

Slide 221

Slide 221 text

No content

Slide 222

Slide 222 text

No content

Slide 223

Slide 223 text

No content

Slide 224

Slide 224 text

No content

Slide 225

Slide 225 text

No content

Slide 226

Slide 226 text

No content

Slide 227

Slide 227 text

“What if you have to translate an interface into many languages? The length of words is unpredictable. How do you manage it across devices? 
 — Michael Scharnagl

Slide 228

Slide 228 text

No content

Slide 229

Slide 229 text

No content

Slide 230

Slide 230 text

No content

Slide 231

Slide 231 text

No content

Slide 232

Slide 232 text

No content

Slide 233

Slide 233 text

No content

Slide 234

Slide 234 text

No content

Slide 235

Slide 235 text

No content

Slide 236

Slide 236 text

“Dealing with “above-the-fold” CSS can be annoying — it has to be maintained and can’t be cached properly. Is there a better way?

Slide 237

Slide 237 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • With HTTP/2, HTTP-requests are cheap.
 Use the “scout” approach with many small files! • Inlining critical CSS is an overhead in HTTP/2 world.
 Server push is helpful but slow. Load CSS in series.

Slide 238

Slide 238 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • Inlining critical CSS is an overhead in HTTP/2 world.
 Server push is helpful but slow. Load CSS in series. 
 
 
 
 …content…
 • We’ve moved away from…

Slide 239

Slide 239 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • Inlining critical CSS is an overhead in HTTP/2 world.
 Server push is helpful but slow. Load CSS in series. 
 
 
 
 
 /* Critical CSS styles */ 
 
 
 • …towards:

Slide 240

Slide 240 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS 
 
 
 
 
 /* Critical CSS styles, plus: */
 article, .comments, aside, footer { display: none; }
 
 
 loadCSS("full.css"); /* or rest.css + critical.css */
 
 
 
 • …and then:

Slide 241

Slide 241 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • A simple, “recommended” “HTTP/2” way: 
 
 
 
 
 
 
 
 …content…


Slide 242

Slide 242 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • But “progressive CSS” way is even better: …
 
 
 
 …
 
 
 …
 
 
 …
 …content…


Slide 243

Slide 243 text

HTTP/1.1 Deployment Strategy Deploying Critical CSS • Multi-Stage CSS loading removes the need for
 critical CSS, and provides sequential rendering. • Browser behavior supports the technique;
 browsers block rendering when necessary.

Slide 244

Slide 244 text

No content

Slide 245

Slide 245 text

“You’ve built a perfect grid with perfectly sized thumbnail images (e.g. squared size), but when the client uploads images with incorrect dimensions, they are squished into the rectangle, incorrectly resized. How do you manage this issue?

Slide 246

Slide 246 text

No content

Slide 247

Slide 247 text

No content

Slide 248

Slide 248 text

“For img src, we can use object-fit property in CSS to “letterbox” the images, preserving the ratio, or crop the images inside the block. For background images, we can apply background-size exactly the same way.

Slide 249

Slide 249 text

No content

Slide 250

Slide 250 text

No content

Slide 251

Slide 251 text

No content

Slide 252

Slide 252 text

No content

Slide 253

Slide 253 text

No content

Slide 254

Slide 254 text

No content

Slide 255

Slide 255 text

No content

Slide 256

Slide 256 text

“What if you wanted the color of the SVG icon to inherit the color property of a button in which it resides? Can we use CSS alone
 (no SASS/LESS) to establish this relationship? 
 — Osvaldas Valutis

Slide 257

Slide 257 text

No content

Slide 258

Slide 258 text

No content

Slide 259

Slide 259 text

No content

Slide 260

Slide 260 text

No content

Slide 261

Slide 261 text

No content

Slide 262

Slide 262 text

No content

Slide 263

Slide 263 text

No content

Slide 264

Slide 264 text

No content

Slide 265

Slide 265 text

No content

Slide 266

Slide 266 text

“HTTP cache is unreliable. Is there any way to keep assets such as fonts, sprites or CSS/JS files in the cache and improving performance for subsequent visits in general?

Slide 267

Slide 267 text

No content

Slide 268

Slide 268 text

Service Workers: Foundation • Service worker is a background process running JS. It behaves like a proxy server on a user’s device. • Websites register a service worker; it then intercepts all network traffic between the site and the outside world. • Once installed, browsers dispatch events to the service worker first, for each network request. • Goal: a reliable “native” proxy that would deliver content when users are both online and offline.

Slide 269

Slide 269 text

No content

Slide 270

Slide 270 text

Offline Strategy • Depending on complexity, we might use offline caching, background processes, push notifications… • A common offline strategy is quite simple: — Explicitely cache resources like CSS, JS, fonts, images;
 — Cache the homepage to display it when network fails;
 — For other pages, have a “fallback” offline page. • We need to register a Service worker first.

Slide 271

Slide 271 text

Offline Strategy • We need to register a Service worker first. • JavaScript:
 if (navigator.serviceWorker) {
 navigator.serviceWorker.register(
 '/sw.js', {
 scope: '/'
 });
 }
 
 • sw.js sits in the root to act on any request; otherwise it acts on requests to a directory in which it resides.

Slide 272

Slide 272 text

Offline Strategy • JavaScript:
 if (navigator.serviceWorker) {
 navigator.serviceWorker.register(
 '/sw.js', {
 scope: '/'
 });
 }
 
 • sw.js sits in the root to act on any request; otherwise it acts on requests to a directory in which it resides. • Caching of sw.js is capped for 24h via Cache-Control.
 Browsers will review the file when accessing the site.

Slide 273

Slide 273 text

Offline Strategy • sw.js sits in the root to act on any request; otherwise it acts on requests to a directory in which it resides. • Next, we need to install the registered service worker. self.addEventListener('install', function (event) {
 event.waitUntil(updateStaticCache());
 });
 
 // Update 'version' if you need to refresh the cache
 var staticCacheName='static';
 var version='v1::';

Slide 274

Slide 274 text

Offline Strategy • Next, we need to install the registered service worker. self.addEventListener('install', function (event) {
 event.waitUntil(updateStaticCache());
 });
 
 // Update 'version' if you need to refresh the cache
 var staticCacheName='static';
 var version='v1::'; • By adding a version number (version), we can easily update the cache later just by updating the version number.

Slide 275

Slide 275 text

Offline Strategy • We’ll populate cache with updateStaticCache(). // Store core files in a cache (incl. 'offline' page)
 function updateStaticCache() {
 return caches.open(version + staticCacheName)
 .then(function (cache) {
 return cache.addAll([
 'js/scripts.js',
 'css/styles.css',
 'images/logo.svg',
 'fonts/webfont.woff',
 '/',
 '/offline']);
 });
 };

Slide 276

Slide 276 text

Offline Strategy • Now we can activate the service worker. We’ll clean up any outdated caches (checking the version number). self.addEventListener('activate', function (event) {
 event.waitUntil(
 caches.keys()
 .then(function (keys) {
 // Remove caches whose name is no longer valid
 return Promise.all(keys
 .filter(function (key) {
 return key.indexOf(version) !== 0; })
 .map(function (key) {
 return caches.delete(key); })
 );
 })
 );
 });

Slide 277

Slide 277 text

No content

Slide 278

Slide 278 text

Offline Strategy • Register a service worker ✓ • Install a service worker ✓ • Versioning setup for a service worker ✓ • Cache population setup for a service worker ✓ • Activate a service worker ✓ • Managing cache for a service worker ✓ • Intercepting requests with a service worker.

Slide 279

Slide 279 text

Offline Strategy self.addEventListener('fetch', function (event) {
 var request = event.request;
 // Always fetch non-GET requests from network
 if (request.method !== 'GET') {
 event.respondWith(
 fetch(request)
 .catch(function () {
 return caches.match('offline.html');
 }); 
 ); 
 return;
 } • The fetch event is fired every time the browser is
 going to request a file. We can intercept that request:

Slide 280

Slide 280 text

No content

Slide 281

Slide 281 text

No content

Slide 282

Slide 282 text

Offline Strategy • For HTML requests, try the network first. If it fails,
 try to fetch cache. If all fails, show the offline page. • For file requests, try to fetch files from cache first.
 If it fails, make a network request. If it fails, use fallback.

Slide 283

Slide 283 text

if (request.headers.get('Accept').indexOf('text/html') !== -1) {
 event.respondWith(
 fetch(request)
 .then(function (response) {
 // Put a copy of this page in the cache
 var copy = response.clone();
 caches.open(version + staticCacheName)
 .then(function (cache) {
 cache.put(request, copy);
 }); 
 return response; }) .catch(function () {
 return caches.match(request)
 .then(function (response) {
 return response || caches.match('/offline.html'); })
 })
 );
 return;
 }

Slide 284

Slide 284 text

if (request.headers.get('Accept').indexOf('text/html') !== -1) {
 event.respondWith(
 fetch(request)
 .then(function (response) {
 // Put a copy of this page in the cache
 var copy = response.clone();
 caches.open(version + staticCacheName)
 .then(function (cache) {
 cache.put(request, copy);
 }); 
 return response; }) .catch(function () {
 return caches.match(request)
 .then(function (response) {
 return response || caches.match('/offline.html'); })
 })
 );
 return;
 }

Slide 285

Slide 285 text

Offline Strategy • For HTML requests, try the network first. If it fails,
 try to fetch cache. If all fails, show the offline page. • For file requests, try to fetch files from cache first.
 If it fails, make a network request. If it fails, use fallback.

Slide 286

Slide 286 text

// For non-HTML, try cache first, then fall back to the network 
 event.respondWith(
 caches.match(request)
 .then(function (response) {
 return response || fetch(request)
 .catch(function () {
 // If request is img, show offline placeholder
 if (request.headers.get('Accept').
 indexOf('image') !== -1) {
 return new Response(
 '', { headers: { 'Content-
 Type': 'image/svg+xml' }}
 );
 }
 });
 })
 );
 


Slide 287

Slide 287 text

Offline Strategy • Register a service worker ✓ • Install a service worker ✓ • Versioning setup for a service worker ✓ • Cache population setup for a service worker ✓ • Activate a service worker ✓ • Managing cache for a service worker ✓ • Intercepting requests with a service worker ✓

Slide 288

Slide 288 text

Service Workers Gotchas • Service workers require a secure connection
 (HTTPS) and are based on ES6 Promises. • Cache API is completely separate from HTTP cache.
 Response is a stream; to cache it, you need to copy it first. • A service worker can have multiple caches and can be registered many times; the browser will figure it out.

Slide 289

Slide 289 text

Service Workers Gotchas • If a service worker is broken, browsers will
 skip the code and fall back to the network. • Service workers use only asynchronous APIs.
 E.g. they can’t work with localStorage (synchronous).

Slide 290

Slide 290 text

No content

Slide 291

Slide 291 text

No content

Slide 292

Slide 292 text

No content

Slide 293

Slide 293 text

No content

Slide 294

Slide 294 text

No content

Slide 295

Slide 295 text

No content

Slide 296

Slide 296 text

No content

Slide 297

Slide 297 text

No content

Slide 298

Slide 298 text

No content

Slide 299

Slide 299 text

No content

Slide 300

Slide 300 text

No content

Slide 301

Slide 301 text

No content

Slide 302

Slide 302 text

“Is there any way to isolate expensive components, similar to lazy loading, and paint important content faster using CSS alone? 
 — Michael Scharnagl

Slide 303

Slide 303 text

The contain property is a primitive for isolating style, layout and paint. It allows us to limit a specific DOM sub-tree and the rest of the document with native boundaries.

Slide 304

Slide 304 text

• With the contain property, we can define priorities for loading and painting CSS components. • Third-party widgets
 Delay expensive layout with contain: strict. • Off-screen modules
 Delay expensive paints with contain: paint. • Container queries
 Focus on the local scope with contain: strict.

Slide 305

Slide 305 text

• With the contain property, we can define priorities for loading and painting CSS components. • Third-party widgets
 Delay expensive layout with contain: strict. • Off-screen modules
 Delay expensive paints with contain: paint. • Container queries
 Focus on the local scope with contain: strict. • Browser support is coming.
 Enabled by default in Chrome 52.

Slide 306

Slide 306 text

No content

Slide 307

Slide 307 text

No content

Slide 308

Slide 308 text

“When using web fonts, we want users to be able to access the content as fast as possible, yet also avoid irritating repaints and reflows in the browser. What would be the best font loading strategy today?

Slide 309

Slide 309 text

No content

Slide 310

Slide 310 text

No content

Slide 311

Slide 311 text

No content

Slide 312

Slide 312 text

No content

Slide 313

Slide 313 text

No content

Slide 314

Slide 314 text

Web Fonts Dilemma • The choice of formats depends on browser support: • WOFF (Web Open Font Format) • TTF (TrueType) • OTF (OpenType) • EOT (Embedded OpenType) • SVG Fonts (Scalable Vector Graphics) • WOFF2 (Web Open Font Format 2)

Slide 315

Slide 315 text

Web Fonts Dilemma • WOFF2 has the best compression, but isn’t supported by older Android/iOS. WOFF is. • Old Android and iOS support TTF and OTF; Internet Explorer 6–8 needs EOT. • SVG doesn’t support OpenType features. 
 Not supported in IE, Chrome or Firefox.

Slide 316

Slide 316 text

Web Fonts Dilemma • WOFF2 has the best compression, but isn’t supported by older Android/iOS. WOFF is. • Old Android and iOS support TTF and OTF; Internet Explorer 6–8 needs EOT. • SVG doesn’t support OpenType features. Supported in Chrome, Safari, Opera. • Strategy: WOFF/2 with TTF/OTF and EOT for IE 6–8; not SVG. Best compression always wins.

Slide 317

Slide 317 text

Declaring @font-face • We can use bulletproof @font-face syntax to avoid common traps along the way: • CSS:
 @font-face { 
 font-family: 'Elena Regular'; 
 src: url('elena.eot?#iefix') format('embedded-opentype'),
 url('elena.woff2') format('woff2'),
 url('elena.woff') format('woff'),
 url('elena.otf') format('opentype');
 }

Slide 318

Slide 318 text

Declaring @font-face • If you want only smart browsers (IE9+) to download fonts, declaration can be shorter: • CSS:
 @font-face { 
 font-family: 'Elena Regular'; 
 src: url('elena.woff2') format('woff2'),
 url('elena.woff') format('woff'),
 url('elena.otf') format('opentype');
 }

Slide 319

Slide 319 text

• CSS:
 @font-face { 
 font-family: 'Elena Regular'; 
 src: url('elena.woff2') format('woff2'),
 url('elena.woff') format('woff'),
 url('elena.otf') format('opentype');
 } • When a font family name is used in CSS, browsers match it against all @font-face rules, download web fonts, display content.

Slide 320

Slide 320 text

• When a font family name is used in CSS, browsers match it against all @font-face rules, download web fonts, display content. • CSS:
 body { 
 font-family: 'Skolar Regular',
 AvenirNext, Avenir, /* iOS */
 'Roboto Slab', 'Droid Serif', /* Android */
 'Segoe UI', /* Microsoft */ 
 Georgia, 'Times New Roman', serif; /* Fallback */
 }

Slide 321

Slide 321 text

• CSS:
 body { 
 font-family: 'Skolar Regular',
 AvenirNext, Avenir, /* iOS */
 'Roboto Slab', 'Droid Serif', /* Android */
 'Segoe UI', /* Microsoft */ 
 Georgia, 'Times New Roman', serif; /* Fallback */
 } • HTML:
 
 
 
 
 try{Typekit.load();}catch(e){}

Slide 322

Slide 322 text

No content

Slide 323

Slide 323 text

• Once DOM and CSSOM are constructed, if @font-face matches, a font will be required. • If fonts aren’t cached yet, they will be requested, downloaded and applied, deferring rendering.

Slide 324

Slide 324 text

No content

Slide 325

Slide 325 text

• FOUT (Flash Of Unstyled Text): show content in fallback fonts first, then switch to web fonts. • FOIT (Flash Of Invisible Text): no content displayed until the font becomes available.

Slide 326

Slide 326 text

No content

Slide 327

Slide 327 text

CSS Font Loading API • Native browser API à la Web Font Loader, with a 
 FontFace object representing @font-face rules. • JavaScript:
 var elena_reg = new FontFace(
 'Elena Regular',
 'url(elena_reg.woff) format("woff"),' + 
 'url(elena_reg.otf) format("otf")', 
 { weight: 'regular', unicodeRange: 'U+0-7ff' } 
 );

Slide 328

Slide 328 text

• JavaScript:
 document.fonts.load('1em elena_reg')
 .then(function() {
 var docEl = document.documentElement;
 docEl.className += ' fonts-ready‘;
 }).catch(function () { 
 var docEl = document.documentElement;
 docEl.className += ' fonts-failed';
 }); • JavaScript:
 var elena_reg = new FontFace(
 'Elena Regular',
 'url(elena_reg.woff) format("woff"),' + 
 'url(elena_reg.otf) format("otf")', 
 { weight: 'regular', unicodeRange: 'U+0-7ff' } 
 );

Slide 329

Slide 329 text

• JavaScript:
 document.fonts.load('1em elena_reg')
 .then(function() {
 var docEl = document.documentElement;
 docEl.className += ' fonts-ready‘;
 }).catch(function () { 
 var docEl = document.documentElement;
 docEl.className += ' fonts-failed';
 }); • CSS:
 .fonts-loaded h1 {
 font-family: "Elena Regular";
 }

Slide 330

Slide 330 text

• JavaScript:
 document.fonts.load('1em elena_reg’)
 .then(function() {
 var docEl = document.documentElement;
 docEl.className += ' fonts-ready’;
 }).catch(function () { 
 var docEl = document.documentElement;
 docEl.className += ' fonts-failed’;
 }); • CSS:
 .fonts-loaded h1 {
 font-family: "Elena Regular";
 font-rendering: "block 0s swap infinite"; // FOUT
 // font-rendering: "block 3s swap infinite"; // FOIT
 }

Slide 331

Slide 331 text

• JavaScript:
 document.fonts.load('1em elena_reg’)
 .then(function() {
 var docEl = document.documentElement;
 docEl.className += ' fonts-ready’;
 }).catch(function () { 
 var docEl = document.documentElement;
 docEl.className += ' fonts-failed’;
 }); • CSS:
 .fonts-loaded h1 {
 font-family: "Elena Regular";
 // font-rendering: "block 0s swap infinite"; // FOUT
 font-rendering: "block 3s swap 3s"; // FOIT, at most 3sec
 }

Slide 332

Slide 332 text

No content

Slide 333

Slide 333 text

No content

Slide 334

Slide 334 text

No content

Slide 335

Slide 335 text

“What if you have a large photo that requires a transparent shadow? PNG is too large in file size, and JPEG isn’t good enough in quality. Trick: create a regular non- transparent JPG and an 8-bit PNG (alpha mask) and load both images inside an SVG container.

Slide 336

Slide 336 text

No content

Slide 337

Slide 337 text

No content

Slide 338

Slide 338 text


 
 • hero-image.svg:


Slide 339

Slide 339 text

• HTML/CSS:
 , background: url("hero-image.svg") 
 
 • hero-image.svg:


Slide 340

Slide 340 text

No content

Slide 341

Slide 341 text

No content

Slide 342

Slide 342 text

No content

Slide 343

Slide 343 text

“How do you efficiently scale up / down any UI component (e.g. a slider or calendar) and keep all the proportions intact—without fiddling with width, height or border-radius manually? 
 — @simurai

Slide 344

Slide 344 text

No content

Slide 345

Slide 345 text

No content

Slide 346

Slide 346 text

“By sneaking a Trojan horse into your components. We use rem for components “root” and em for sub- parts of the components. Then, by adjusting the font-size of the root, we adjust all size-related CSS properties of a component at once. 
 — @simurai

Slide 347

Slide 347 text

No content

Slide 348

Slide 348 text

No content

Slide 349

Slide 349 text

No content

Slide 350

Slide 350 text

“What if you wanted to style a block with a light background color differently than if the same block has a dark background image? Or reverse text color based on bg color automatically in CSS? 
 — Osvaldas Valutis

Slide 351

Slide 351 text

No content

Slide 352

Slide 352 text

No content

Slide 353

Slide 353 text

No content

Slide 354

Slide 354 text

No content

Slide 355

Slide 355 text

No content

Slide 356

Slide 356 text

No content

Slide 357

Slide 357 text

“The mix-blend-mode property defines how an element’s content should blend with its background. Use mix-blend-mode: difference or mix-blend-mode: darken to have backgrounds, shapes, and text all interact in subtle/interesting ways. 
 — Robin Rundle

Slide 358

Slide 358 text

• CSS:
 .letterbox { background-color: #fff; }
 .letterbox-letter { fill: #f7ff33;
 mix-blend-mode: darken;
 /* The background is replaced with the color that is darker, otherwise it is left as it was. */ }

Slide 359

Slide 359 text

“What if you want all links to have an underline except the ones you specify? Or you want all
  • ’s in the navigation to have a right border, except the last one. Normally you would use :last-child (or extra class) to overwrite a default CSS rule. 
 — Ire Aderinokun
  • Slide 360

    Slide 360 text

    No content

    Slide 361

    Slide 361 text

    No content

    Slide 362

    Slide 362 text

    “You’ve built an alert message box. To be resilient to failure, how can we make sure that the box will be hidden when there is no content within it? — Ire Aderinokun

    Slide 363

    Slide 363 text

    No content

    Slide 364

    Slide 364 text

    No content

    Slide 365

    Slide 365 text

    “Mobile browsers will wait approx. 300ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap.

    Slide 366

    Slide 366 text

    No content

    Slide 367

    Slide 367 text

    The touch-action property in CSS can be used to disable this behaviour. With touch-action: manipulation, the user agent may consider touches that begin on the element only for the purposes of scrolling and continuous zooming.

    Slide 368

    Slide 368 text

    No content

    Slide 369

    Slide 369 text

    “What if you have 3 containers (thumbnails gallery), each 33% width, but they also have padding defined in em values, and border defined in px values? The layout might break because width doesn’t consider those values.

    Slide 370

    Slide 370 text

    No content

    Slide 371

    Slide 371 text

    “We can apply the good ol’ IE Box Model to ensure that whenever we define width (or height), it always includes the padding and the border as well. We do that by applying box-sizing: border-box to pretty much everything.

    Slide 372

    Slide 372 text

    No content

    Slide 373

    Slide 373 text

    No content

    Slide 374

    Slide 374 text

    No content

    Slide 375

    Slide 375 text

    No content

    Slide 376

    Slide 376 text

    No content

    Slide 377

    Slide 377 text

    “What if you want to create some sort of visual distortion? E.g. for headlines or hero banners or prominent boxes. Can we achieve it with CSS/HTML alone?

    Slide 378

    Slide 378 text

    No content

    Slide 379

    Slide 379 text

    No content

    Slide 380

    Slide 380 text

    No content

    Slide 381

    Slide 381 text

    No content

    Slide 382

    Slide 382 text

    “There are many little details that often make an experience just annoying. E.g. an age prompt once you try to access an age-restricted website. Can we do better?

    Slide 383

    Slide 383 text

    No content

    Slide 384

    Slide 384 text

    No content

    Slide 385

    Slide 385 text

    No content

    Slide 386

    Slide 386 text

    No content

    Slide 387

    Slide 387 text

    No content

    Slide 388

    Slide 388 text

    No content

    Slide 389

    Slide 389 text

    • Email verification is unnecessary
 60% of users consistently copy/paste their email when asked to verify it in the checkout.

    Slide 390

    Slide 390 text

    • Email verification is unnecessary
 Remove the email verification field altogether, or use inline autocomplete or “review” page instead.

    Slide 391

    Slide 391 text

    No content

    Slide 392

    Slide 392 text

    No content

    Slide 393

    Slide 393 text

    No content

    Slide 394

    Slide 394 text

    No content

    Slide 395

    Slide 395 text

    No content

    Slide 396

    Slide 396 text

    No content

    Slide 397

    Slide 397 text

    No content

    Slide 398

    Slide 398 text

    No content

    Slide 399

    Slide 399 text

    No content

    Slide 400

    Slide 400 text

    No content

    Slide 401

    Slide 401 text

    No content

    Slide 402

    Slide 402 text

    No content

    Slide 403

    Slide 403 text

    No content

    Slide 404

    Slide 404 text

    No content

    Slide 405

    Slide 405 text

    No content

    Slide 406

    Slide 406 text

    No content

    Slide 407

    Slide 407 text

    No content

    Slide 408

    Slide 408 text

    No content

    Slide 409

    Slide 409 text

    No content

    Slide 410

    Slide 410 text

    No content

    Slide 411

    Slide 411 text

    No content

    Slide 412

    Slide 412 text

    No content

    Slide 413

    Slide 413 text

    No content

    Slide 414

    Slide 414 text

    No content

    Slide 415

    Slide 415 text

    No content

    Slide 416

    Slide 416 text

    No content

    Slide 417

    Slide 417 text

    No content

    Slide 418

    Slide 418 text

    No content

    Slide 419

    Slide 419 text

    No content

    Slide 420

    Slide 420 text

    No content

    Slide 421

    Slide 421 text

    No content

    Slide 422

    Slide 422 text

    No content

    Slide 423

    Slide 423 text

    No content

    Slide 424

    Slide 424 text

    No content

    Slide 425

    Slide 425 text

    No content

    Slide 426

    Slide 426 text

    No content

    Slide 427

    Slide 427 text

    No content

    Slide 428

    Slide 428 text

    No content

    Slide 429

    Slide 429 text

    No content

    Slide 430

    Slide 430 text

    No content

    Slide 431

    Slide 431 text

    No content

    Slide 432

    Slide 432 text

    No content

    Slide 433

    Slide 433 text

    No content

    Slide 434

    Slide 434 text

    No content

    Slide 435

    Slide 435 text

    No content

    Slide 436

    Slide 436 text

    Summary


    Slide 437

    Slide 437 text

    No content

    Slide 438

    Slide 438 text

    No content

    Slide 439

    Slide 439 text

    No content

    Slide 440

    Slide 440 text

    No content

    Slide 441

    Slide 441 text

    No content

    Slide 442

    Slide 442 text

    No content

    Slide 443

    Slide 443 text

    No content

    Slide 444

    Slide 444 text

    No content

    Slide 445

    Slide 445 text

    No content

    Slide 446

    Slide 446 text

    No content

    Slide 447

    Slide 447 text

    No content

    Slide 448

    Slide 448 text

    No content

    Slide 449

    Slide 449 text

    No content

    Slide 450

    Slide 450 text

    No content

    Slide 451

    Slide 451 text

    No content

    Slide 452

    Slide 452 text

    No content

    Slide 453

    Slide 453 text

    No content

    Slide 454

    Slide 454 text

    No content

    Slide 455

    Slide 455 text

    No content

    Slide 456

    Slide 456 text

    No content

    Slide 457

    Slide 457 text

    No content

    Slide 458

    Slide 458 text

    No content

    Slide 459

    Slide 459 text

    No content

    Slide 460

    Slide 460 text

    No content

    Slide 461

    Slide 461 text

    Summary
 
 
 — apply pseudo-elements on broken images
 — contain: strict reduces painting costs
 — fluid type with font-size: calc (1em + 1vw)
 — nested links with 
 — highlight row/column with pseudo-elements
 — control table-layout with table-layout: fixed
 — padded lines with the box-shadow trick
 — consider critical progressive CSS (HTTP/2)
 — use object-fit: cover to letterbox images
 — use native variables with CSS currentColor

    Slide 462

    Slide 462 text

    Summary
 
 
 — service workers can boost performance a lot
 — test scan levels to improve image delivery
 — early fetch of critical resources with preload
 — add interface screens to pattern libraries
 — use the Font Loading API to load web fonts
 — replace age prompt with a year prompt
 — replace country selector with autosuggest
 — replace email verification with email review
 — load maps/lightboxes conditionally
 — experiment and produce something creative.

    Slide 463

    Slide 463 text

    Thank you.

    Slide 464

    Slide 464 text

    Image credits • Front cover: Geometric Wallpapers
 by Simon C Page (http://simoncpage.co.uk/ blog/2012/03/ipad-hd-retina-wallpaper/) • Sections illustrations: “bisous les copains”, by Guillaume Kurkdjian (http:// bisouslescopains.tumblr.com/)
 • Techniques: by (tremendous) web design community.