Styles in the world of components

Styles in the world of components

Kyrylo Yakovenko(@blia)

Styles in the world of components

CSS with preprocessors

Preprocessors bring a lot of cool features to CSS:

It's good for HTML documents 👍, but not for small components👎.

Problem

			<link rel="stylesheet" href="node_modules/comp1/style.css">
			<link rel="stylesheet" href="node_modules/comp2/style.css">
			<link rel="stylesheet" href="node_modules/comp3/style.css">
			<link rel="stylesheet" href="node_modules/comp4/style.css">
			...
		

Webpack

JavaSctipt is entry point

			//component1/index.js
			import styles from './styles.css';
		
			//component2/index.js
			import styles from './styles.css';
		

Problem

			let btnClass = 'btn';
			if (this.state.isPressed) btnClass += ' btn-pressed';
			else if (this.state.isHovered) btnClass += ' btn-over';
			<button className={btnClass}>;
		

Classnames

			import classNames from 'classnames';
			const btnClass = classNames({
				btn: true,
				'btn-pressed': this.state.isPressed,
				'btn-over': !this.state.isPressed && this.state.isHovered
			});
			<button className={btnClass}>;
		

Problem

Global scope

CSS-modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.

Problem

			import classNames from 'classnames';
			import styles from './styles.css';
			const btnClass = classNames({
				styles['btn']: true,
				styles['btnPressed']: this.state.isPressed,
				styles['btnOver']: this.state.isHovered
			});
			<button className={btnClass}>;

		

Classnames ❤️ CSS-modules

			import classNames from 'classnames/bind';
			import styles from './styles.css';
			var cx = classNames.bind(styles);
			var btnClass = cx({
				btn: true,
				btnPressed: this.state.isPressed,
				btnOver: this.state.isHovered
			});
			<button className={btnClass}>;

		

React Native & CSS in JS

			const styles = StyleSheet.create({
				red: {
					color: 'red',
					fontSize: 16
				},
			});
			<Text style={styles.red}>just red</Text>
		

Problem?

Actually, no.

Tagged template literals

			const styles = StyleSheet.create({
				red: css`
					color: red;
					font-size: 16;
				`,
			});
			<Text style={styles.red}>just red</Text>
		

Styled-components

			import styled from 'styled-components';
			const RedText = styled.Text`
				color: red;
				font-size: 16;
			`;
			<RedText>just red</RedText>
		

Cool?

Yes!

Styled-components

			import styled from 'styled-components';
			const RedText = styled.Text`
				color: red;
				font-size: 16;
			`;
			const BlueText = styled.Text`
				color: blue;
				font-size: 16;
			`;
			<RedText>just red</RedText>
			<BlueText>just blue</BlueText>
		

Sheet mode

			import css from 'my-css-lib';
			const { RedText, BlueText } = css`
				.red-text {
					color: red;
					font-size: 16;
				}
				.blue-text {
					color: blue;
					font-size: 16;
				}`;
			<RedText>just red</RedText>
			<BlueText>just blue</BlueText>
		

No selectors

			import css from 'my-css-lib';
			const { RedText, BlueText } = css`
				.red-text {
					color: red;
					font-size: 16;
				}
				.blue-text {
					color: blue;
					font-size: 16;
				}`;
			<RedText>just red</RedText>
			<BlueText>just blue</BlueText>
		

Specified tags

			import css from 'my-css-lib';
			const { RedText, BlueText } = css`
				div.red-text {
					color: red;
					font-size: 16;
				}
				p.blue-text {
					color: blue;
					font-size: 16;
				}`;
			<RedText>just red</RedText>
			<BlueText>just blue</BlueText>
		

Extending components

			import css from 'my-css-lib';
			import ActionButton from './action-button';
			const { LoginButton } = css`
				ActionButton.login-button {
					background-color: green;
					font-size: 16;
				}`;
			<LoginButton>Log in</LoginButton>
		

Pseudo-classes

			import css from 'my-css-lib';
			const { Link } = css`
				a.link {
					color: blue;
					text-decoration: underline;
					:hover {
						text-decoration: none;
					}
				}`;
			<Link href="/">Home</Link>
		

And statuses (special boolean props)

			import css from 'my-css-lib';
			const { Link } = css`
				a.link {
					color: blue;
					text-decoration: underline;
					:hover {
						text-decoration: none;
					}
					:is-active {
						color: red;
					}
				}`;
			<Link href="/" isActive={isHomePage}>Home</Link>
		

Context (props)

			import css from 'my-css-lib';
			const { Link } = css`
				a.link {
					color: ${props => props.isActive ? 'red' : 'blue'};
					text-decoration: underline;
					:hover {
						text-decoration: none;
					}
				}`;
			<Link href="/" isActive={isHomePage}>Home</Link>
		

Every declaration is a function

			import css from 'my-css-lib';
			const { MyButton } = css`
				.my-button {
					color: blue;
					display: block;
				}`;
		

Every declaration is a function

			import css from 'my-css-lib';
			const { MyButton } = css`
				.my-button {
					css.color('blue');
					css.display('block');
				}`;
		

Every function returns an object

			import css from 'my-css-lib';
			const { MyButton } = css`
				.my-button {
					...{color: 'blue'};
					...{display: 'block'};
				}`;

		

css.use

			import css from 'my-css-lib';
			css.use('box', size => ({width: size, height: size}));
			const { MyBox } = css`
				.my-box {
					background-color: green;
					box: 20px;
				}`;
		

css.use

			import css from 'my-css-lib';
			css.use('box', size => ({width: size, height: size}));
			const { MyBox } = css`
				.my-box {
					background-color: green;
					width: 20px;
					height: 20px;
				}`;
		

css.use

			import css from 'my-css-lib';
			const box = size => ({width: size, height: size});
			css.use({ box });
			const { MyBox } = css`
				.my-box {
					background-color: green;
					box: 20px;
				}`;
		

NameSpase

			import css from 'my-css-lib';
			import polished from 'polished';
			css.use('po', polished);
			const { MyCell } = css`
				.my-cell {
					display: table-cell;
					-po-ellipsis: 250px;
				}`;
		

Context (props) + css.use

			import css from 'my-css-lib';
			const activeColor =
				color => ctx => ({color: ctx.isActive ? color : 'blue'});
			css.use({ activeColor });
			const { Link } = css`
				a.link {
					active-color: red;
					text-decoration: underline;
				}`;
			<Link href="/" isActive={isHomePage}>Home</Link>
		

Local scope

			import css from 'my-css-lib';
			const activeColor =
				color => ctx => ({color: ctx.isActive ? color : 'blue'});
			const { Link } = css`
				a.link {
					-local-active-color: red;
					text-decoration: underline;
				}`;
			<Link href="/" isActive={isHomePage}>Home</Link>
		

Local scope

			import css from 'my-css-lib';
			const activeColor =
				color => ctx => ({color: ctx.isActive ? color : 'blue'});
			const { Link } = css`
				a.link {
					-active-color: red;
					text-decoration: underline;
				}`;
			<Link href="/" isActive={isHomePage}>Home</Link>
		

Thanks!

twitter.com/blia
github.com/blia