Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Compilers in Styling Web UI

Ryan Tsao
November 30, 2017

Compilers in Styling Web UI

Slides from my talk at DotCSS 2017

Ryan Tsao

November 30, 2017
Tweet

Other Decks in Programming

Transcript

  1. import styled from "styled-components"; export const Button = styled.button` padding:

    30px 0; margin: 8px 16px; width: 60px; `; background: transparent; color: white; ${props G> props.primary && css` background: white; color: palevioletred; `};
  2. export const OnBrandButton = styled(Button)` color: floralwhite; background: midnightblue; `;

    import styled from "styled-components"; export const Button = styled.button` padding: 30px 0; margin: 8px 16px; width: 60px; `; background: transparent; color: white; ${props J> props.primary && css` background: white; color: palevioletred; `};
  3. export const OnBrandButton = styled(Button)` color: floralwhite; background: midnightblue; `;

    import styled from "styled-components"; export const Button = styled.button` padding: 30px 0; margin: 8px 16px; width: 60px; `; background: transparent; color: white; ${props J> props.primary && css` background: white; color: palevioletred; `}; import {OnBrandButton} from "./styles";
  4. export const OnBrandButton = styled(Button)` color: floralwhite; background: midnightblue; `;

    import styled from "styled-components"; export const Button = styled.button` padding: 30px 0; margin: 8px 16px; width: 60px; `; background: transparent; color: white; ${props J> props.primary && css` background: white; color: palevioletred; `}; import {OnBrandButton} from "./styles";
  5. export const OnBrandButton = styled(Button)` color: floralwhite; background: midnightblue; `;

    import styled from "styled-components"; export const Button = styled.button` padding: 30px 0; margin: 8px 16px; width: 60px; `; background: transparent; color: white; ${props J> props.primary && css` background: white; color: palevioletred; `}; import {OnBrandButton} from "./styles";
  6. import styled from "styled-components"; import {darken, lighten} from "polished"; const

    Button = styled.button` color: midnightblue; border: 2px solid midnightblue; background: floralwhite; &:hover { color: ${props G> lighten(0.3, "midnightblue")}; border: 2px solid ${props G> lighten(0.3, "midnightblue")}; background: ${props G> darken(0.1, "floralwhite")}; } `; render(<Button>Hello World</Button>);
  7. import styled from "styled-components"; // import {darken, lighten} from "polished";

    const Button = styled.button` color: midnightblue; border: 2px solid midnightblue; background: floralwhite; &:hover { color: ${props E> "#4b4bd7"}; border: 2px solid ${props E> "#4b4bd7"}; background: ${props E> "#ffe9bd"}; } `; render(<Button>Hello World</Button>);
  8. import styled, {ThemeProvider} from "styled-components"; import {darken, lighten} from "polished";

    const Button = styled.button` color: ${props E> props.theme.fg}; border: 2px solid ${props E> props.theme.fg}; background: ${props E> props.theme.bg}; &:hover { color: ${props E> lighten(0.3, props.theme.fg)}; border: 2px solid ${props E> lighten(0.3, props.theme.fg)}; background: ${props E> darken(0.1, props.theme.bg)}; } `; const theme = { fg: "midnightblue", bg: "floralwhite" }; render( <ThemeProvider theme={theme}> <Button>Hello World</Button> </ThemeProvider> );
  9. 170 kB JavaScript bundle (gzip) Moto G4 - Slow 3G

    via Addy Osmani - “Cost of JavaScript”
  10. 170 kB JavaScript bundle (gzip) ~3.4 s in Fetch Moto

    G4 - Slow 3G via Addy Osmani - “Cost of JavaScript”
  11. ~2.0 s in Parse/Compile 170 kB JavaScript bundle (gzip) ~3.4

    s in Fetch Moto G4 - Slow 3G via Addy Osmani - “Cost of JavaScript”
  12. ~2.0 s in Parse/Compile 170 kB JavaScript bundle (gzip) ~3.4

    s in Fetch ~1.5 s in Execution Moto G4 - Slow 3G via Addy Osmani - “Cost of JavaScript”
  13. Primary Secondary Tertiary Normal blue Normal gray Normal red Hover

    25% darker Hover 25% darker Hover 25% darker ! !
  14. Primary Secondary Tertiary Normal blue Normal gray Normal red Hover

    25% darker Hover 25% darker Hover 25% darker ! ! Normal Hover 80% lighter Normal Hover 80% lighter Normal Hover 80% lighter ! ! Enabled ✅ Disabled ❌
  15. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant] });
  16. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  17. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  18. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } }); const dynamicStyle = await ( await fetch("https://css-in-js.io/json") ).json(); const dynamicProp = dynamicStyle.prop; const dynamicVal = dynamicStyle.val;
  19. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } }); const dynamicStyle = await ( await fetch("https://css-in-js.io/json") ).json(); const dynamicProp = dynamicStyle.prop; const dynamicVal = dynamicStyle.val; const style = { color: "red", padding: "4px", [dynamicProp]: dynamicVal };
  20. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } }); const dynamicStyle = await ( await fetch("https://css-in-js.io/json") ).json(); const dynamicProp = dynamicStyle.prop; const dynamicVal = dynamicStyle.val; const style = { color: "red", padding: "4px", [dynamicProp]: dynamicVal }; Conditional logic ≠ Dynamic styles
  21. ! Dynamic styles ! Dynamic styles ! Dynamic styles Static

    styles ! Dynamic styles Static styles + Conditional logic
  22. Label { color: red; } Label:hover { color: white; }

    Label:prop(mode == "emphasis") { font-weight: bold; } import {Label} from "./styles.css" <Label /> <Label mode="emphasis" />
  23. fn int_to_string (x : u32) { match x { 0

    | 1 => "zero or one", 2 ... 4 => "two through four", 5 => "five!", } }
  24. fn int_to_string (x : u32) { match x { 0

    | 1 => "zero or one", 2 ... 4 => "two through four", 5 => "five!", } }
  25. fn int_to_string (x : u32) { match x { 0

    | 1 => "zero or one", 2 ... 4 => "two through four", 5 => "five!", _ => "six or greater", } }
  26. type state = { variant: "primary" | "secondary" | "tertiary",

    disabled: boolean }; const Button = (props: state) >> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  27. Button [ ] type state = { variant: "primary" |

    "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) @> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  28. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) A> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  29. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background @variant { "primary" <> blue "secondary" <> gray "tertiary" <> red } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) <> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  30. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled) { ("primary", false) @> blue ("primary", true) @> blue ("secondary", false) @> gray ("secondary", true) @> gray ("tertiary", false) @> red ("tertiary", true) @> red } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) @> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  31. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled) { ("primary", false) @> blue ("primary", true) @> blue BC lighten(90) ("secondary", false) @> gray ("secondary", true) @> gray BC lighten(90) ("tertiary", false) @> red ("tertiary", true) @> red BC darken(90) } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) @> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  32. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) B> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  33. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) B> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  34. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> #4887ba ("primary", true, _) B> #c2deff ("secondary", false, false) B> gray ("secondary", false, true) B> #9b9b9b ("secondary", true, _) B> #dfdfdf ("tertiary", false, false) B> red ("tertiary", false, true) B> #be455a ("tertiary", true, _) B> #ffd3d8 } ] type state = { variant: "primary" | "secondary" | "tertiary", disabled: boolean }; const Button = (props: state) B> ({ background: { primary: props.disabled ? lighten("blue", 90) : "blue", secondary: props.disabled ? lighten("gray", 90) : "gray", tertiary: props.disabled ? lighten("red", 90) : "red" }[props.variant], "&:hover": { background: !props.disabled && { primary: darken("blue", 25), secondary: darken("gray", 25), tertiary: darken("red", 25) }[props.variant] } });
  35. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] Element Style Sheets Experimental!
  36. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] import {Button} from "./styles.ess"; const App = () B> ( <div> <Button variant="primary">Hello World</Button> <Button variant="secondary" disabled>Hi</Button> </div> );
  37. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] .a { background: blue } .b:hover { background: #4887ba } .c, .c:hover { background: #c2deff } .d { background: gray } .e { background: #9b9b9b } .f, .f:hover { background: #dfdfdf } .g { background: red } .h:hover { background: #be455a } .i, .i:hover { background: #ffd3d8 } import {Button} from "./styles.ess"; const App = () B> ( <div> <Button variant="primary">Hello World</Button> <Button variant="secondary" disabled>Hi</Button> </div> );
  38. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] export const Button = props B> { const {variant, disabled, ...rest} = props; return <div className={buttonClassName(props)} {...rest} />; }; function buttonClassName({variant, disabled}) { switch (variant) { case "primary": if (disabled) return "c"; return "a b"; case "secondary": if (disabled) return "f"; return "d e"; case "tertiary": if (disabled) return "i"; return "g h"; } } .a { background: blue } .b:hover { background: #4887ba } .c, .c:hover { background: #c2deff } .d { background: gray } .e { background: #9b9b9b } .f, .f:hover { background: #dfdfdf } .g { background: red } .h:hover { background: #be455a } .i, .i:hover { background: #ffd3d8 } import {Button} from "./styles.ess"; const App = () B> ( <div> <Button variant="primary">Hello World</Button> <Button variant="secondary" disabled>Hi</Button> </div> );
  39. Button [ @variant = "primary" | "secondary" | "tertiary" @disabled

    = boolean background (@variant, @disabled, @:hover) { ("primary", false, false) B> blue ("primary", false, true) B> blue DE darken(25) ("primary", true, _) B> blue DE lighten(90) ("secondary", false, false) B> gray ("secondary", false, true) B> gray DE darken(25) ("secondary", true, _) B> gray DE lighten(90) ("tertiary", false, false) B> red ("tertiary", false, true) B> red DE darken(25) ("tertiary", true, _) B> red DE lighten(90) } ] .button--variant-primary { background: blue } .button--variant-primary:hover { background: #4887ba } .button--variant-primary.button--disabled, .button--variant-primary.button--disabled:hover { background: #c2deff } .button--variant-secondary { background: gray } .button--variant-secondary:hover { background: #9b9b9b } .button--variant-secondary.button--disabled, .button--variant-secondary.button--disabled:hover { background: #dfdfdf } .button--variant-tertiary { background: red } .button--variant-tertiary:hover { background: #be455a } .button--variant-tertiary.button--disabled, .button--variant-tertiary.button--disabled:hover { background: #ffd3d8 }
  40. background: silver padding: 14px min-height: 500px background: teal padding: 14px

    min-height: 500px background: silver text-align: center border-radius: 3px color: #fff background: teal text-align: center border-radius: 3px color: #fff
  41. background: silver padding: 14px min-height: 500px background: teal padding: 14px

    min-height: 500px background: silver text-align: center border-radius: 3px color: #fff background: teal text-align: center border-radius: 3px color: #fff .a { } .g { } .c { } .b { } .d { } .e { } .f { } background: silver background: teal padding: 14px min-height: 500px text-align: center border-radius: 3px color: #fff Atomic CSS "a b c f" "a b c g" "d e f" "d e g"
  42. background: silver padding: 14px min-height: 500px background: teal padding: 14px

    min-height: 500px background: silver text-align: center border-radius: 3px color: #fff background: teal text-align: center border-radius: 3px color: #fff .a { } .g { } .c { } .b { } .d { } .e { } .f { } background: silver background: teal padding: 14px min-height: 500px text-align: center border-radius: 3px color: #fff Atomic CSS .a { } .c { } .b { } .d { } background: silver background: teal padding: 14px min-height: 500px text-align: center border-radius: 3px color: #fff Atomic++ CSS "a c" "a d" "b c" "b d"