├── 01-box-model.md
├── 02-resets.md
├── 03-components-vs-layout.md
├── 04-grids.md
├── README.md
└── img
├── grid
├── add-element.png
├── calc-margin.png
├── flex-basis.png
├── flex-grow.png
├── flex-wrap.png
├── flex.png
├── gutter.png
├── html.png
├── mobile.png
├── negative-margin-bg.png
└── negative-margin.png
├── layout-1.png
├── twitter-desktop.png
└── twitter-mobile.png
/01-box-model.md:
--------------------------------------------------------------------------------
1 | # Understanding the Box Model
2 |
3 | Whether styling a single element or a larger layout, the first thing to understand is the "Box Model".
4 | This is how elements decide how much space to occupy and where to place themselves.
5 |
6 | When thinking about the size of an element there are 4 different parts or properties that make up a single element's "Box Model":
7 |
8 | 1. Content (width/height) - This is the size of the text content within an element or the set `width` and `height` properties
9 | 2. Padding - This is the whitespace between the content and the border of an element
10 | 3. Border - This is a indiviually styled and colored wrapper surrounding an element
11 | 4. Margin - This is the whitespace between the current element and the next element on the page
12 |
13 | ## Fixing the Box Model
14 |
15 | By default `width` and `height` only dictate the size of the "Content" area of an element.
16 | This means that if you have an element that is `width: 100%; background: red` and add a `padding: 1rem`, then the default setting is for the element's background to take up 100% of the parent element's width **PLUS** another `2rem` (that's `1rem` for both the left and right sides of the element).
17 | This behavior can be hard to wrap your mind around since most people associate the background of an element with the SIZE of an element.
18 | Luckily this behavior can be fixed by adding one simple rule to your CSS:
19 |
20 | ```css
21 | *, *::before, *::after {
22 | box-sizing: border-box;
23 | }
24 | ```
25 |
26 |
27 | This means that `width` and `height` on all elements (and pseudo-elements) includes the `padding` and `border` for that element.
28 |
29 | ## How to Use `width` and `height`
30 |
31 | 1. Whenever possible, avoid specifying `width` or `height` - this can cause overflow issues as text resizes or dynamic content is added via an API or CMS (Content Management System)
32 | 2. If you have to specify `width` or `height`... DONT DO IT!
33 | 3. Seriously, you still want to specify `width` or `height`? Can you use `flex-basis` instead?
34 | 4. Did `flex-basis` not work out? Ok, but at least use a `%` measurement
35 |
36 | ## Choosing Between `padding`, `margin`, and `border`
37 |
38 | 1. Does this whitespace need to have a color different from your background?
39 | * Yes: `border`
40 | * No: Keep Going
41 | 2. Do you have a background?
42 | * Yes: Should the whitespace be inside or outside of the background?
43 | - Inside: `padding`
44 | - Outside: `margin`
45 | * No: Keep Going
46 | 3. Will this element EVER *possibly* have it's own background?
47 | * Yes: Should the whitespace be inside or outside of the future background?
48 | - Inside: `padding`
49 | - Outside: `margin`
50 | * No: Go back and ask your designer to make sure, then either look at the previous step or keep going
51 | 4. Did you already set a hard `width`, `height`, or `flex-basis`?
52 | * Yes: Did you use `calc` to account for future margins?
53 | - Yes: `margin`
54 | - No: `padding`
55 | * No: `margin`
56 |
57 | ## How `display` Changes the "Box Model"
58 |
59 | The `display` property can vastly alter the way that an element's box model is created.
60 | Let's look at some features of this (note this assumes the element isn't within a "flex parent" and not `position: absolute` or `fixed`)
61 |
62 | * `display: block` and `display: flex`
63 | * Defaults `width` to `auto` which is `100%` but will automatically account for margins
64 | * Margin and padding on all sides is accounted for when laying out other elements
65 | * Setting hard `width` or `height` alters the size of the element
66 | * Next element will always drop to a new line unless floated or in a flex context
67 | * `display: inline-block`
68 | * Defaults `width` to `auto` which only takes up the size of the text or internal content
69 | * Margin and padding on all sides is accounted for when laying out other elements
70 | * Setting hard `width` or `height` alters the size of the element
71 | * Next `inline`, `inline-block`, or text content will be on the same line if any parent `width` is remaining
72 | * Whitespace between elements will show up
73 | * `display: inline`
74 | * Width and height are completely ignored and only text content is applied
75 | * Margin top and bottom are completely ignored
76 | * Margin left and right are accounted for as usual
77 | * Padding top and bottom changes the rendering of background but does not shift the layout of other elements
78 | * Padding left and right are accounted for as usual
79 |
80 | ## Need Help Deciding Between Display Properties
81 |
82 | 1. Are you trying to modify the behavior of whitespace and child elements within the selected element?
83 | * Yes: `display: flex`
84 | * No: Continue on
85 | 2. Are you trying to modify a text property like `text-decoration`, `font-weight`, `color`, etc within text?
86 | * Yes: `display: inline` - **NOTE** this almost always should be already applied by your element choice `a`, `span`, `strong`, `em`
87 | * No: Continue on
88 | 3. Is this element inline with EXISTING text content? (Note this does not include things like "levels")
89 | * Yes: Should spaces between text and the current element be accounted for?
90 | * Yes: `display: flex`
91 | * No: Possibly make the parent element `display: flex`
92 | * No: `display: block`
93 |
94 | ---
95 |
96 | Let's continue by looking at common CSS resets: [NEXT](02-resets.md)
97 |
--------------------------------------------------------------------------------
/02-resets.md:
--------------------------------------------------------------------------------
1 | # Resets
2 |
3 | One common practice from the last few years of web development is to reset everything!!!
4 | While this can be useful to having a clean slate to work from, it often means that work is doubled.
5 | This bloats stylesheets and makes rendering more taxing.
6 |
7 | In contrast to this, look at [this site](http://motherfuckingwebsite.com/) (I apologize for the strong language).
8 | These are the default styles we're working with.
9 | By leveraging these styles along with a few logical improvements, we can get a good launch pad for building beautiful sites.
10 |
11 | ## Body Margin
12 |
13 | How many sites do you know that have absolutely no change in background?
14 | I'm even including the navbar!
15 |
16 | When changing backgrounds, 99.9999999999% of the time you will want the background (I'm including horizontal box-shadows and borders in this too) to span from sea to shining sea!
17 | So 5/5 dentists agree that while the default margin set on the `body` element is nice when our stylesheet fails to load, it makes it really annoying to get full-width backgrounds working.
18 | Fixing this takes one simple CSS rule:
19 |
20 | ```css
21 | body {
22 | margin: 0;
23 | }
24 | ```
25 |
26 | > **NOTE** this one is really easy to see: it looks like there is an `8px` border around the page, you likely forgot this one little thing.
27 |
28 | > **ALSO NOTE** this body reset is a great place to put your default background and font-family to knock those out in one go.
29 |
30 | ## Lists
31 |
32 | Think of all the places you use `ul` elements:
33 |
34 | * Collections
35 | * Nav Groups
36 | * Tabs
37 | * Button Groups
38 | * Article Lists
39 | * Bulleted Lists
40 |
41 | Except for the last one, none of the "lists" above need bullets!
42 | So why should a bulleted list be your default style for `ul` elements?
43 | Well it's nice when there's absolutely no styling, but for everything else there's a quick and easy reset:
44 |
45 | ```css
46 | ul {
47 | padding-left: 0;
48 | list-style: none;
49 | }
50 | ```
51 |
52 | ## Making the Stylesheet Responsive Again
53 |
54 | Do you know what it takes to break the amazing nature of the built in, completely responsive browser stylesheet?
55 | One single image that is wider than the device screen-width!
56 |
57 | Since even the original iPhone saved photos at a 1600x1200 resoution, it's really easy to get LARGE images unless you remember to save for web or use an image processing library on your server (like [gm](https://npm.org/packages/gm)).
58 | This means a single user upload could wreck massive damage on a site.
59 | But protecting from this is easy:
60 |
61 | ```css
62 | img {
63 | max-width: 100%;
64 | }
65 | ```
66 |
67 | ## THAT'S IT
68 |
69 | What more do you want from a reset?
70 | A lot of the browser defaults are fairly sensible and give a good sense of typographic scale.
71 | Sure it's not perfect, but it makes time to initial review REALLY fast.
72 |
73 | ## TLDR;
74 |
75 | So far, our stylesheet looks like this:
76 |
77 | ```css
78 | *, *::before, *::after {
79 | box-sizing: border-box;
80 | }
81 |
82 | body {
83 | margin: 0;
84 | }
85 |
86 | ul {
87 | padding-left: 0;
88 | list-style: none;
89 | }
90 |
91 | img {
92 | max-width: 100%;
93 | }
94 | ```
95 |
96 | ---
97 |
98 | Let's continue by looking at what makes something a part of layout and what makes something a "Component": [NEXT](03-components-vs-layout.md)
99 |
--------------------------------------------------------------------------------
/03-components-vs-layout.md:
--------------------------------------------------------------------------------
1 | # Components vs Layouts
2 |
3 | One concept that can drastically reduce the complexity of your CSS and increase the reusability of your HTML is to separate the concepts of what is part of a "Component" and what is "Layout".
4 |
5 | > Layout is like a bookshelf and then components are like the things that get to move around on the bookshelf - Brad Westfall
6 |
7 | The point of separating Layout from Components makes it easier to move components around.
8 | For instance consider a single Tweet on Twitter.
9 | This would be a component, both on desktop:
10 |
11 | 
12 |
13 | And on mobile:
14 |
15 | 
16 |
17 | But notice that even when this tweet is shown on mobile and takes up the full-width of the page, it's rendering is the same!
18 | This is the definition of a good Component, even as the layout changes it can adapt and fill the space needed.
19 | It is also independent of the grid (or lack of grid) that may contain it.
20 |
21 | This also makes reusability of layout primitives easier when they do not carry the baggage of styling like `borders`, `box-shadows`, `background`, or text properties.
22 |
23 | Consider the following layout:
24 |
25 | 
26 |
27 | The left side is about half of the page size and then there are two quarter grid items.
28 | At first glance, you might think that the HTML may look like:
29 |
30 | ```html
31 |
42 | ```
43 |
44 | But this actually is a tougher way of breaking down this layout since it limits new content that could be added to the right side of the page.
45 | Instead, let's look at how we can reuse the `columns` primitive to make a fluid and dynamic grid:
46 |
47 | ```html
48 |
67 | ```
68 |
69 | See this example on [Codepen](http://codepen.io/rtablada/pen/oYYNvN)
70 |
71 | Notice that by breaking down the left and right into halves and then creating a new row of columns in the right side, there is now room for more items on the right to fit into the grid system.
72 | Try adding a `.column+.orange` to the codepen HTML within the `right-x` div to see this in action!
73 |
74 | If the grid items and sizes had borders or any styles not pertaining to layout, then this flexibility would not be possible!
75 |
76 | Also as a note, components should not contain layout style elements, so for instance while it may be tempting to use the `column` classes above to recreate the tweet "Component" picture to text ratio, this would add weight and complexity if the layout classes were to change.
77 |
78 | ---
79 |
80 | Let's continue by how we can use the concepts of layout to create a responsive grid and set of containers for a full responsive site: [NEXT](04-grids.md)
81 |
--------------------------------------------------------------------------------
/04-grids.md:
--------------------------------------------------------------------------------
1 | # Grids and Containers
2 |
3 | Grids and containers can be rather intimidating when building layout.
4 | With libraries like Bootstrap packing a mind-boggling 1051 lines of code for just a 12 column responsive grid, it's no wonder that companies think that responsive grids are best left to a framework!
5 | Luckily with a few tricks, you'll be making an even better, more responsive, and more maintainable grid than one you'd find off the shelf.
6 |
7 | let's start with some basic HTML for our grid.
8 |
9 | ```html
10 |
24 | ```
25 |
26 | 
27 |
28 | Here we're using BEM naming conventions to make it easier to see that `grid__item`s belong directly within `grid` blocks.
29 | We'll also be using SCSS to help see how these items belong together.
30 | This will also help to see how `display: flex` changes child elements.
31 | LET'S GET STARTED!!!
32 |
33 | First we need to have our `grid` line up our four `grid__item`s next to each other using flexbox:
34 |
35 | ```scss
36 | .grid {
37 | display: flex;
38 | }
39 | ```
40 |
41 | 
42 |
43 | Next we need our `grid__item` to be 1/4 of the grid width for flexibility later we'll use `flex-basis` instead of `width` (more on this decision later).
44 |
45 | ```scss
46 | .grid {
47 | display: flex;
48 |
49 | &__item {
50 | flex-basis: 25%;
51 | }
52 | }
53 | ```
54 |
55 | 
56 |
57 | Now that we have 1/4s we should get whitespace between our `grid__item` elements using margin:
58 |
59 | ```scss
60 | .grid {
61 | display: flex;
62 |
63 | &__item {
64 | flex-basis: 25%;
65 | margin: 1rem;
66 | }
67 | }
68 | ```
69 |
70 | 
71 |
72 | Notice that this did two things:
73 |
74 | * Since `flex-shrink` defaults to `1`, the `grid__item`s have shrunk from their last size.
75 | * Since all of the elements have margin on all sides, the red `grid__item` no longer lines up with the heading that isn't part of our grid.
76 |
77 | Frameworks often complicate this by requiring all elements to be within grid containers, but this adds a lot of unnecessary weight to our HTML!
78 | Instead, we can get around this with a single line of CSS (oh and no `:nth-of-type` selectors that often complicate grids):
79 |
80 | ```scss
81 | .grid {
82 | display: flex;
83 | margin: -1rem;
84 |
85 | &__item {
86 | flex-basis: 25%;
87 | margin: 1rem;
88 | }
89 | }
90 | ```
91 |
92 | 
93 |
94 | Here the `-1rem` margin stretches the `grid` div actually beyond the grey background of it's parent element.
95 | This can be seen by quickly giving a purple temporary background to our `grid` div:
96 |
97 | 
98 |
99 | But what if we add another element to our HTML:
100 |
101 | ```html
102 |
103 |
106 |
109 |
112 |
115 |
118 |
119 | ```
120 |
121 | 
122 |
123 | Uh oh!!!
124 | Looks like now we have a 5 element grid even though our `flex-basis` is `25%`?
125 | We can prevent this by adding `flex-wrap` on our `grid`:
126 |
127 | ```scss
128 | .grid {
129 | display: flex;
130 | flex-wrap: wrap;
131 | margin: -1rem;
132 |
133 | &__item {
134 | flex-basis: 25%;
135 | margin: 1rem;
136 | }
137 | }
138 | ```
139 |
140 | 
141 |
142 | But now there's only three elements on each row in our `grid`?
143 | If we recall the ["Box Model"](01-box-model.md), even with `box-sizing: border-box` our `width` doesn't account for `margin`s.
144 | So to fix this we can use the `calc` function to subtract the left and right margins on our `grid__item`s:
145 |
146 | ```scss
147 | .grid {
148 | display: flex;
149 | flex-wrap: wrap;
150 | margin: -1rem;
151 |
152 | &__item {
153 | flex-basis: calc(25% - 1rem - 1rem);
154 | margin: 1rem;
155 | }
156 | }
157 | ```
158 |
159 | 
160 |
161 | The next step is optional, but in my opinion it makes a really cool grid.
162 | What to do with the `grid__item` that is all by itself.
163 | Here we can leverage flexbox in a few different ways, my personal favorite is to add `flex-grow: 1` to the `grid__item` so that it fills up any remaining space on it's row:
164 |
165 | ```scss
166 | .grid {
167 | display: flex;
168 | flex-wrap: wrap;
169 | margin: -1rem;
170 |
171 | &__item {
172 | flex-basis: calc(25% - 1rem - 1rem);
173 | flex-grow: 1;
174 | margin: 1rem;
175 | }
176 | }
177 | ```
178 |
179 | 
180 |
181 | The last thing we can do is make sure that our grid stacks vertically on mobile using a media query.
182 | For this we can make our `grid` div `flex-direction: column`.
183 | This will make all of the `grid__item`s stack!
184 |
185 | ```scss
186 | .grid {
187 | display: flex;
188 | flex-wrap: wrap;
189 | margin: -1rem;
190 |
191 | &__item {
192 | flex-basis: calc(25% - 1rem - 1rem);
193 | flex-grow: 1;
194 | margin: 1rem;
195 | }
196 |
197 | @media (max-width: 400px) {
198 | flex-direction: column;
199 | }
200 | }
201 | ```
202 |
203 | 
204 |
205 | > **NOTE** Notice that this grid doesn't use any `min-width` or `max-width` settings.
206 | > This is because it should be the responsibility of components to decide when they break down.
207 | > If a tweet needs `20rem` width to render properly, then the grid shouldn't add this limitation since it could have a button column that only needs `4rem`.
208 |
209 |
210 | Here is a [Codepen playground](http://codepen.io/rtablada/pen/ZBBEJP) to work with grids.
211 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CSS Can Be Easy
2 |
3 | This guide is to teach that building responsive sites and applications using CSS can be easier than you might think.
4 | There are a few best practices
5 |
6 | ## Assumptions
7 |
8 | This guide is built around a support stack of IE 11 and modern browsers (evergreen Chrome, Edge, Safari, Firefox, Opera).
9 | IE <11 is no longer supported by Microsoft for even security updates.
10 | This means not only is your team missing out on awesome features like `calc` and flexbox, but continuing to support IE <11 puts your app and more importantly your customers at risk.
11 | To read more about Microsoft's support policy, see: https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support.
12 |
13 | This recommendation guide pretty heavily uses `display: flex`.
14 | Even with the support stack listed above, I would recommend using something like [autoprefixer](https://github.com/postcss/autoprefixer) to fill in gaps in prefixing or experimental features.
15 |
16 | Also, while most everything here should Just Work™, there are a few known flexbox bugs.
17 | To learn more about these, check out the popular [Flexbugs Repo](https://github.com/philipwalton/flexbugs).
18 |
19 | ## Let's Get Started!
20 |
21 | 1. [Box Model](01-box-model.md)
22 | 2. [Resets](02-resets.md)
23 | 2. [Components vs Layout](03-components-vs-layout.md)
24 | 3. [Grids (the Easy Way)](04-grids.md)
25 |
--------------------------------------------------------------------------------
/img/grid/add-element.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/add-element.png
--------------------------------------------------------------------------------
/img/grid/calc-margin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/calc-margin.png
--------------------------------------------------------------------------------
/img/grid/flex-basis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/flex-basis.png
--------------------------------------------------------------------------------
/img/grid/flex-grow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/flex-grow.png
--------------------------------------------------------------------------------
/img/grid/flex-wrap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/flex-wrap.png
--------------------------------------------------------------------------------
/img/grid/flex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/flex.png
--------------------------------------------------------------------------------
/img/grid/gutter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/gutter.png
--------------------------------------------------------------------------------
/img/grid/html.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/html.png
--------------------------------------------------------------------------------
/img/grid/mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/mobile.png
--------------------------------------------------------------------------------
/img/grid/negative-margin-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/negative-margin-bg.png
--------------------------------------------------------------------------------
/img/grid/negative-margin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/grid/negative-margin.png
--------------------------------------------------------------------------------
/img/layout-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/layout-1.png
--------------------------------------------------------------------------------
/img/twitter-desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/twitter-desktop.png
--------------------------------------------------------------------------------
/img/twitter-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rtablada/css-can-be-easy/b5ba6246b0e41b7d710ed29e7cf1c08927d67dd6/img/twitter-mobile.png
--------------------------------------------------------------------------------