Современные возможности CSS,
разработка под мобильные устройства

Технопарк, весна, 2024 г.

Стили. Разработка под мобильные устройства
Слайды доступны по ссылке
frontend.tech-mail.ru

Стили и CSS

CSS is awesome

CSS is awesome

PLAY

Сначала был... HTML

Сначала был... HTML

CSS в здании

		html {
			font-size: 62.5%;
			font-family: serif;
		}
		body {
			font-size: 1.8rem;
			line-height: 1.618;
			max-width: 38em;
			margin: auto;
			color: #4a4a4a;
			background-color: #f9f9f9;
			padding: 13px;
		}
		h1, h2, h3, h4, h5, h6 {
			line-height: 1.1;
			font-family: Verdana, Geneva, sans-serif;
			font-weight: 700;
			overflow-wrap: break-word;
			word-wrap: break-word;
			word-break: break-word;
			hyphens: auto;
		}
		...
	

CSS для вёрстки

Table Hell...

		<table cellpadding="0" cellspacing="0" border="0">
		    <tr>
		        <td class="header" colspan="3" height="120px">....</td>
		    </tr>
		    <tr>
		       <td class="menu" valign="top">...</td>
		       <td class="content" valign="top">...</td>
		       <td class="aSide" valign="top">...</td>
		    </tr>
		    <tr>
		        <td class="footer" colspan="3">...</td>
		    </tr>
		</table>
	

Мухи отдельно, котлеты отдельно...

Float

"Обтекаемость" изображений
в тексте

Вёрстка макета страницы на
основе float

Пример
				body {
					padding-left: 200px;
					padding-right: 190px;
					min-width: 240px;
				}
				header, footer {
					margin-left: -200px;
					margin-right: -190px;
				}
				main, nav, aside {
					position: relative;
					float: left;
				}
				main {
					padding: 0 20px;
					width: 100%;
				}
				aside {
					width: 130px;
					padding: 0 10px;
					margin-right: -100%;
				}
				footer {
					clear: both;
				}
			

No Escape

Flexbox layout

Flexbox

		.container-flex {
		    display: flex;
		    flex-direction: column;
		    justify-content: space-between;
		}
	
A Complete Guide to Flexbox

Вёрстка макета страницы на
основе flex

Пример
				body {
					min-height: 100vh;
					display: flex;
					flex-direction: column;
				}
				.container {
					display: flex;
					flex: 1;
				}
				main {
					flex: 1;
					padding: 0 20px;
				}
				nav {
					flex: 0 0 180px;
					padding: 0 10px;
					order: -1;
				}
				aside {
					flex: 0 0 130px;
					padding: 0 10px;
				}
			

Grid layout

Вёрстка макета страницы на
основе Grid Layout

Пример
				body {
					display: grid;
					min-height: 100vh;
					grid-template-columns: 200px 1fr 150px;
					grid-template-rows: min-content 1fr min-content;
				}
				header {
					grid-row: 1;
					grid-column: 1 / 4;
				}
				nav {
					grid-row: 2;
					grid-column: 1 / 2;
					padding: 0 10px;
				}
				main {
					grid-row: 2;
					grid-column: 2 / 3;
					padding: 0 20px;
				}
				aside {
					grid-row: 2;
					grid-column: 3 / 4;
					padding: 0 10px;
				}
				footer {
					grid-row: 3;
					grid-column: 1 / 4;
				}
			

grid-column

Современный CSS

CSS-фильтры

					.image {
					    filter: value;
					}
					 
				

CSS-фильтры

					.image {
					    filter: blur(5px);
					}
					 
				

CSS-фильтры

					.image {
					    filter: brightness(0.5);
					}
					 
				

CSS-фильтры

					.image {
					    filter: contrast(200%);
					}
					 
				

CSS-фильтры

					.image {
					    filter: saturate(400%);
					}
					 
				

CSS-фильтры

					.image {
					    filter: drop-shadow(16px 16px 10px black)
					            grayscale(100%);
					}
					 
				

CSS-транзиции

					.box {
					    transition-property: transform
					                         background-color;
					    transition-duration: 1s;
					    transition-timing-function: ease;
					}
					.box:hover {
					    transform: scale(2.5) rotate(180deg)
					    background-color: palevioletred;
					}
					 
				

CSS-анимации

		@keyframes colors {
		    from {
		        background-color: green;
		    }
		    to {
		        background-color: palevioletred;
		        transform: scale(1.5);
		    }
		}
		 
	

CSS-анимации

		.box {
		    animation-name: colors;
		    animation-duration: 2s;
		    animation-direction: alternate;
		    animation-iteration-count: infinite;
		}
		 
	

CSS-анимации

CSS Animations and Web Animations API

3D-трансформации

		.box {
		    transform-style: preserve-3d;
		    transform: perspective(900px);
		    transform: rotate3d(x, y, z, deg);
		    transform: translate3d(x, y, z);
		    
		}
		 
	

3D-трансформации

CSS-variables

			:root {
			    --my-color: #FFF;
			}
			.color-picker {
			    box-shadow: 0 0 5em var(--my-color, white);
			}
			 
		

CSS-variables from JS

			// get value
			document.documentElement.style
			     .getPropertyValue('--my-color');
			 
			// set value
			document.documentElement.style
			     .setProperty('--my-color', 'green');
			document.documentElement.style
			     .setProperty('--my-color', 'var(--fancy-color)');
			 
		

CSS Houdini

Проект CSS Houdini

CSS Paint API example

Even More CSS Secrets

Окей, новый CSS — это 🔥

Препроцессоры CSS

Тысячи их!

Тысячи их!

SASS

		$dark-color: #4a4a4a
		$light-color: #f9f9f9
		$side-color: #eee
		body
		  color: $dark-color
		  
		header, footer
		  background-color: $dark-color
		  color: $light-color
		  
		main
		  background: $light-color
		nav, aside
		  background: $side-color
	

LESS

		@dark-color: #4a4a4a;
		@light-color: #f9f9f9;
		@side-color: #eee;
		body {
		  color: @dark-color;
		}
		
		header, footer {
		  background-color: @dark-color;
		  color: @light-color;
		}
		
		main {
		  background: @light-color;
		}
		nav, aside {
		  background: @side-color;
		}
	

SCSS

		$font-stack:    Helvetica, sans-serif
		$primary-color: #333
		 
		.login-form {
		    color: $primary-color;
		    &__input {
		        font: 18px $font-stack;
		        &:active {
		            background-color: white;
		        }
		    }
		}
		 
	

SCSS — миксины

		@mixin border-radius($radius) {
		  -webkit-border-radius: $radius;
		     -moz-border-radius: $radius;
		      -ms-border-radius: $radius;
		          border-radius: $radius;
		}
		 
		.button {
		    @include border-radius(10px);
		}
		 
	

PostCSS

Использование PostCSS

		// postcss.config.js
		module.exports = {
		    plugins: [
		        require('precss')({/* ...options */}),
		        require('autoprefixer')({/* ...options */}),
		        ...
		    ]
		}
		 
		// main.js
		import 'styles.css';
		 
	

CSS директивa @supports

		@supports (display: flex) {
		    div { display: flex; }
		}
		 
		@supports not (display: flex) {
		    div { float: left; } /* задан альтернативный стиль */
		}
		 
	

CSS директивa @supports

		@supports (display: -webkit-flex) or
		          (display: -moz-flex) or
		          (display: flex) {
		 
		    /* добавляем сюда ваших клёвых стилей */
		}
		 
	
		// использование в JS
		const supportsFlex1 = CSS.supports('display', 'flex');
		const supportsFlex2 = CSS.supports('(display: flex)');
		 
	

Не забываем про методологии!

Компонентный подход!

CSS Modules

Использование CSS Modules

		/* button.css */
		.button {
		    width: 200px;
		    height: 48px;
		    border-radius: 12px;
		}
		 
		.primary {
		    background-color: green;
		    font-weight: 500;
		}
		 
	

Использование CSS Modules

		// button.js
		import styles from './button.css';
		 
		export default function renderButton (title, primary) {
		    return `
		        <button class="${styles.button} ${primary ? styles.primary : ''}">
		            ${title}
		        </button>
		    `;
		}
		 
	

Использование CSS Modules

		// main.js
		import renderButton from './button.js';
		 
		document.body.innerHTML = `
		    ${renderButton('Вжух!', true)}
		    ${renderButton('Очистить')}
		`;
		 
	

Использование CSS Modules

		<!-- результирующий HTML -->
		 
		<button class="button-213ge1hw primary-jh4gd318">
		    Вжух!
		</button>
		<button class="button-213ge1hw">
		    Очистить
		</button>
		 
	

JSS

Использование JSS

		// main.js
		import jss from 'jss';
		import preset from 'jss-preset-default';
		import color from 'color';
		 
		// One time setup with default plugins and settings
		jss.setup(preset());
		const styles = {
		    button: {
		        width: 200,
		        background: color('blue').darken(0.3).hex(),
		    },
		};
		 
	

Использование JSS

		// ...
		const { classes } = jss.createStyleSheet(styles).attach();
		 
		document.body.innerHTML = `
		    <button class="${classes.button}">
		        Button
		    </button>
		`;
		 
	

Кто придумывает WEB?

W3C — www.w3.org

W3C (World Wide Web Consortium — Консорциум Всемирной паутины) — организация, разрабатывающая и внедряющая технологические стандарты для Всемирной паутины. Консорциум возглавляет Тимоти Джон Бернерс-Ли

Любой стандарт W3C проходит 5 стадий согласования:
и только после этого официально становится рекомендацией W3C

WHATWG — whatwg.org

WHATWG (Web Hypertext Application Technology Working Group) — сообщество людей, заинтересованных в развитии Интернета. Было основано в 2004 году производителями браузеров: Apple, Mozilla Foundation и Opera Software. Основным направлением сообщества является развитие HTML и API, необходимого для веб-приложений.

По сути, является форком W3C. WHATWG была недовольна медленными темпами развития стандартов и уклоном W3C в сторону HTML, основанного на XML-синтаксисе

Сейчас WHATWG активно разрабатывает спецификации: HTML, DOM Standard, Fetch Standard, Web workers, Storage Standard, Streams Standard...

CSS — Cascading Style Sheets

CSS одна из широкого спектра технологий, одобренных консорциумом W3C и получивших общее название «стандарты Web»

wiki.csswg.org — рабочая группа CSS в рамках консорциума W3C

Все CSS-спецификации — www.w3.org/Style/CSS/specs.en.html

CSS is awesome

CSS is awesome
CSS is awesome
CSS is awesome
CSS is awesome

Кроссплатформенная разработка

Статистика по платформам от StatCounter

StatCounter Data

Подходы к разработке под
мобильные устройства

Как определить возможности
устройства?

Медиа-запросы (Media Queries)

A media query is a method of testing certain aspects of the user agent or device that the document is being displayed in

		@media screen and (max-width: 1900px) {
		    .container {
		        width: 70vw;
		        max-width: 1200px;
		    }
		}
		 
	

Использование в CSS

		@media screen and (color) { /* Для цветных экранов */
		    body { background: whitesmoke; }
		}
		 
		/* Для широкоформатных экранов */
		@media screen and (min-device-aspect-ratio: 16/10) {
		    ...
		}
		 
	

Использование в CSS

		@media projection { /* проектор */ }
		@media handheld { /* смартфоны и носимые устройства */ }
		@media tv { /* телевизоры */ }
		@media braille { /* устройства для слабовидящих */ }
		 
		@media (hover) { /* если на устройстве работает hover */ }
		 
		@media (pointer: coarse) { /* тачскрины (низкая точность) */ }
		@media (pointer: fine) { /* мышь или стилус (высокая точность) */ }
		@media (pointer: none) { /* нет курсора (и такое бывает!) */ }
		 
	

Использование в HTML

		<link rel="stylesheet"
		    media="all and (orientation : portrait)"
		    href="portrait.css">
		 
		<link rel="stylesheet"
		    media="all and (orientation : landscape)"
		    href="landscape.css">
		 
	

Единицы измерения длины CSS

Единицы измерения CSS
подробнее

Относительные

Единицы измерения CSS
подробнее

Абсолютные

Типы пикселей — подробнее

Пиксели? Пиксели!

Пиксели? Пиксели!

Пиксели? Пиксели!

HTML-тег <picture>

		<picture> 
				<source
					srcset="<список URL c дескрипторами>" 
					[sizes="<ваши размеры в зависимости от раскладки>"]
					[media="<медиавыражение>"] 
					[type="<mime/type>"] 
				> 
				<source ...>
				<img src="image.jpg" alt="My image" 
		</picture>
		 

	

HTML-тег <picture>

		<img 
				src="images/400.jpg" 
				srcset=" 400w, images/800.jpg 800w, images/1200.jpg 1200w" 
				sizes="(min-width: 700px) 75vw, 100vw"
		> 
	
Retina
		<img 
				src="images/400.jpg" 
				srcset="images/800.jpg 2x, images/1200.jpg 3x" 
				width="400" height="300"
		> 
	

HTML-тег <picture>

		<picture> 
				<source
					media="(min-width: 900px)" 
					srcset="images/original.jpg 1200w"
					sizes="100vw" 
				> 
				<source
					media="(min-width: 700px) 
					srcset="images/800crop.jpg 800w"
					sizes="100vw" 
				> 
				<source ...>
				<img srcset="images/400crop.jpg 400w" sizes="100vw"> 
		</picture>
		 

	

Адаптивность?

Увеличивается в зависимости от media query
		h1 { font-size: 14px; }
		@media (min-width: 320px) {
			h1 { font-size: 20px } 
		}
		@media (min-width: 960px) {
		  h1 { font-size: 40px; } 
		}
		 
	
Увеличивается в зависимости от размера экрана
		h1 { font-size: calc(14px + 5vw); }
		 
	

CSS-locks (или CSS-шлюзы)

		h1 { font-size: 20px; }
		@media (min-width: 320px) {
			h1 { font-size: calc( 3.125vw + 10px ); } 
		}
		@media (min-width: 960px) {
		  h1 { font-size: 40px; } 
		}

		 

	
CSS шлюзы пример
CSS шлюзы еще пример
CSS шлюзы и еще пример

Функция clamp()

При помощи этой функции можно реализовать CSS шлюз встроенными средствами языка.
			clamp(min, value, max)
		
			/* Статические значения */
			width: clamp(200px, 40%,  400px);
			width: clamp(20rem, 30vw, 70rem);
			width: clamp(10vw,  20em, 100vw);

			/* Вычисляемые значения */
			width: clamp(min(10vw, 20rem), 300px, max(90vw, 55rem));
			width: clamp(100px, calc(30% / 2rem + 10px), 900px);
		
Развернутая документация на MDN

Математика CSS-шлюзов

Область просмотра (viewport)

Область просмотра (viewport)

Область просмотра (viewport)

			<meta name="viewport"
			      content="width=device-width, initial-scale=1">
		
Развернутая документация на MDN

CSS-правило @viewport

		@viewport {
		     width: device-width;
		     height: device-height;
		     zoom: 2;
		     user-zoom: fixed;
		}
	
Это правило считается устаревшим. Тем не менее, иногда может встречаться в коде.
Развернутая документация на MDN

Оптимизация графики для Retina-экранов

Нативное взаимодействие

Нативное взаимодействие

Проблемы:

Проблема: зоопарк событий

События mouse-events:

Проблема: зоопарк событий

События touch-events:

Проблема: зоопарк событий

Проблема: зоопарк событий

События pointer-events:

pointer-events

Проблема: 300-ms задержка

Между событием touchend и click проходит 300-350ms
		html {
		    touch-action: manipulation;
		    touch-action: auto;
		    touch-action: pan-y; /* pan-x */
		    touch-action: pinch-zoom;
		}
		 
	

Проблема: нет нужных событий

Проблема: нет нужных событий

		// HammerJS - http://hammerjs.github.io/
		const hammertime = new Hammer(element, options);
		hammertime.on('swipe', function(event) {
		    console.log(event);
		});
		 
	

Accessibility — тред на Habr

ARIA — Accessible Rich Internet
Applications — MDN

		<!-- роли ARIA -->
		<header role="banner">
		<div role="alert">Алерт!</div>
		 
		<!-- атрибуты ARIA -->
		<input type="radio" aria-checked="true">
		<button aria-hidden="true" style="display: none;">
		    Эта кнопка скрыта
		</button>
		 
	

Семантика для циников, Вадим Макеев

What Makes a Good Mobile Site?

Mobile Web App Checklist

Что ещё?

Web App Manifest

Progressive Web App
		<link rel=manifest href="/manifest.json">
		 
	

Web App Manifest

		{
		    "name": "Calculator",
		    "short_name": "Calc",
		    "lang": "ru-RU",
		    "start_url": "/index.html",
		    "display": "fullscreen", // standalone, minimal-ui, browser
		    "orientation": "landscape", // portrait, any
		    "background_color": "#0F0848",
		    "theme_color": "#0F0848",
		    "related_applications": [ ... ]
		    "prefer_related_applications": false
		    "icons": [ ... ]
		}
		 
	

Web App Manifest

		{
		    "icons": [ {
		            "src": "/imgs/icon-16.png",
		            "type": "image/png",
		            "sizes": "16x16"
		        }, {
		            "src": "/imgs/icon-24.png",
		            "type": "image/png",
		            "sizes": "24x24"
		        } ]
		}
		 
	

Add to Home Screen (A2HS)

Apple meta-tags

		<link rel=apple-touch-icon href="/imgs/icon-152.png">
		<meta name=theme-color content=#0F0848>
		 
		<meta name=application-name content="Calc">
		<meta name=apple-mobile-web-app-title content="Calc">
		 
		<meta name=mobile-web-app-capable content=yes>
		<meta name=apple-mobile-web-app-capable content=yes>
		<meta name=apple-mobile-web-app-status-bar-style content=#0F0848>
		 
	
Apple Meta Tags Insanity

Полезные ссылки

Всем спасибо!