CSS Grid Layout
Robust Layout Using Rows r Columns
R. Scott Granneman r Jans Carton
© 2014 R. Scott Granneman
Last updated 2020-07-17
You are free to use this work, with certain restrictions.
3.3 For full licensing information, please see the last slide/page.
Notes & URLs for this presentation can be found…
» underneath the link to this slide show on
granneman.com
» at files.granneman.com/presentations/webdev/CSS-
Layout.txt
As of October 2018
As of March 2020
Flexbox
vs Grid
Flexbox is for laying out elements in a particular
direction along a (sometimes wrapped) line
Grid assigns objects within a matrix of columns & rows
❶ ❷ ❸ ❹ ❺ ❻ ❼
❽ ❾ ❿
Flexbox
❸ ❺ ❶
❹
❷
Grid
With every other layout method except grid, you can
visualize the layout itself via the HTML
Grid, however, defines all layout in the CSS — the
HTML doesn’t necessarily tell you anything about the
actual rendered layout other than certain grid items
exist inside a grid container
Grid is ultimately about using CSS to define layout
scaffolding & then placing rendered boxes onto that
scaffolding
Dev tools for grid allow you to inspect something
besides the DOM items you’ve seen with other layouts;
instead, with grid you see the layout structures
Concepts
& Terms
Grid container defines the grid structure
Grid is composed of lines, cells, areas, & tracks
Grid items are placed into areas
Grid gutters are thick lines between tracks
Grid container
» creates a grid layout context
» can be bigger (or smaller) than the
grid itself
Grid lines divide the grid, & they are
key to understanding grid layout
This grid has 8 lines
Grid lines are numbered
Space between 4 adjacent grid lines
defines a grid cell
This grid has 9 cells
Grid area is defined by 4 (not
necessarily adjacent) grid lines
Grid area is surrounded by 4 grid
lines around any number of cells
A cell is an area, but not all areas are
cells!
How many areas are in this grid?
Space between 2 adjacent grid lines
defines grid tracks of columns or
rows
A column track
How many total tracks are in this
grid?
A column track
How many total tracks are in this
grid?
6!
Grid items are placed into grid
areas based on grid lines — in this
case, an area equal to 1 cell
Grid items are placed into areas
that can span more than 1 cell
All direct children of grid container
are grid items*
* With a few exceptions
This grid has 9 cells but only 1 item
Cells are not part of the DOM so
you cannot select them with CSS
Grid item between:
» row lines 1 & 2, & column lines
1&2
» row lines -3 & -4, & column
lines -3 & -4
» any others?
Grid item between:
» row lines 3 & 4, & column lines
2&3
» row lines -1 & -2, & column
lines -2 & -3
» any others?
Grid gutters are basically thick lines
creating space between tracks
Your First
Grid
display: grid
grid-template-columns
grid-template-rows
grid-gap/gap
grid-row-start
grid-row-end
grid-column-start
grid-column-end
Create a grid layout context
with display: grid
Nothing to see because we
triggered the grid layout but
haven’t yet built a grid 1
Build the grid with tracks using
grid-template-columns &
grid-template-rows
Now we see the grid container
because there’s a grid inside it 2
Add space between tracks using
grid-gap
Note the grid is now 340×340 3
Add grid items, which are placed
automatically by default 4
Place grid items using line numbers
5
Inspecting
Grids
Firefox easily has the best grid inspector tools
Right-click on a grid & select Inspect Element
1
1. Indicates a grid container 2
2. Click to reveal grid
Line numbers appear — positive
& negative — as do gutters
Under Layout > Grid, you can
change what appears, including
the colors of the lines
Chromium-based browsers are surprisingly not nearly
as useful
Nothing much here…
Hover over the
grid container
Hover over the
grid item
Safari’s Inspector does nothing special for grid, so it’s
pretty useless
Triggering
Grid Layout
display: grid (<inside>)
display: block grid (<outside> <inside>)
Creates a grid layout context inside the box:
» Grid box aligns vertically (because block)
» Creates the grid container
» Container can be bigger (or smaller) than the grid
itself
» Immediate children become grid items
Note that there are no grid items yet!
Each grid item creates a new layout
context, so each grid item can itself
be a flow, flexbox, or grid container
Track Basics
When you create tracks, you define
» whether they are columns or rows
» how many tracks there are
» the size of the tracks
» optional names for the lines adjacent to the tracks
grid-template-columns
grid-template-rows
grid-template-columns & grid-template-rows are
foundational for creating the grid tracks, which in turn
define the grid
grid-template-columns
Explicitly defines size & number of grid columns, &
line names via a <track list>
Can mix & match any units: px, em, %, fr …
<track list> can be…
» a single size value for 1 column: 200px
» multiple size values for >1 columns: 200px 1fr 300px
» a mix of values & line names: 200px [hpl] 300px
grid-template-rows
Explicitly defines size & number of grid rows via a
<track list>
Same rules as grid-template-columns
We will mention grid-template-columns & grid-
template-rows constantly throughout the rest of this
presentation
grid-
template- –* 16 52 10.1 10.3 57 57
columns-
grid-
template- –* 16 52 10.1 10.3 57 57
rows-
* IE uses the older grid-columns & grid-rows, which autoprefixer should take care of for you
Placing Items
5 ways to place grid items
» Automatic
» Numbered lines
» Named lines
» Named areas
» Spans
By default grid items are placed automatically in the
same order as your code, as you’ve seen*
You can position grid items manually, however
* Details & exceptions having to do with grid-auto-flow will be covered later
grid-row-start grid-area
grid-row-end
grid-row
grid-column-start
grid-column-end
grid-column
Values:
» <integer>: positive or negative
» <custom-ident>: name you choose
» span <integer> && <custom-ident>: tracks to
stretch across
Numbered Lines
grid-row-start
grid-row-end
grid-column-start
grid-column-end
Properties that determine where 1 edge of a grid item is
placed
Values specify start or end line; e.g.,
grid-row-start: 3
grid-row
grid-column
Shorthand properties that combine -start & -end for a
given track direction (row or column)
Values specify start and end lines; e.g.,
grid-row: grid-row-start / grid-row-end
grid-row: 3/5
grid-area
Shorthand property that combines -start & -end for
both track directions
Value specifies 4 start & end lines; e.g.,
grid-area: grid-row-start / grid-column-
start / grid-row-end / grid-column-end
grid-area: 2/2/4/5
grid-row-start – 16 52 10.1 10.3 57 57
grid-row-end – 16 52 10.1 10.3 57 57
grid-column-
– 16 52 10.1 10.3 57 57
start
grid-column-end – 16 52 10.1 10.3 57 57
grid-row – 16 52 10.1 10.3 57 57
grid-column – 16 52 10.1 10.3 57 57
What number is this line?
What number is this line?
2 and -3
Negative Line Numbers
Use negative numbers to count
backwards from the ends
Why negative line numbers?
The number of tracks might change, & you don’t know
the line number for the end
1 always represents the start
-1 always represents the end
4 is fine because we know
the number of tracks
4 no longer works — the
number of tracks changed
-1 fixes it no matter how
many tracks
Named Lines
You can assign names to some or all grid lines, & those
names are mixed with your track sizes
The names, which you create, must go inside []
grid-template-rows: [start] 100px [line-2]
100px [line-3] 100px [end]
You do not have to name every single line, & can
instead name just the key lines in your layout
grid-template-rows: [start] 100px 100px
[line-3] 100px [end]
You can give a line more than 1 name if it serves more
than one purpose
grid-template-rows: [start] 100px 100px
[line-3 foo bar] 100px [end]
You can use the same name on multiple lines
grid-template-rows: [start] 100px 100px
[line-3 foo bar] 100px [end foo]
Once lines have names, you can use the name to place
an item rather than a line number
You can mix named lines & line numbers, but that will
lead to instant insanity
header-start
sidebar-start
header-end
body-start
body-end
sidebar-end
sidebar-end
header-end
header-start body-end
body-start sidebar-start
header-start
sidebar-start
header-end
body-start
body-end
sidebar-end
sidebar-end
header-end
header-start body-end
body-start sidebar-start
header-start
sidebar-start
header-end
body-start
body-end
sidebar-end
sidebar-end
header-end
header-start body-end
body-start sidebar-start
header-start
sidebar-start
header-end
body-start
body-end
sidebar-end
sidebar-end
header-end
header-start body-end
body-start sidebar-start
Named Areas
grid-template-areas
grid-area
We know how to layout a grid by positioning grid items
via grid lines
Another method: use grid template areas
grid-template-areas
Defines named areas in the grid
All named areas must be rectangular
1
body is a
rectangle Everything lays out nicely!
body is no
longer a
rectangle
Ruh-roh
grid-area
Places grid item in a named area
1
When you define a named area, the lines around those
areas are automatically assigned implicit line names
You can use these implicit line names when placing
items via named lines
1
header-start
header-end
body-start
sidebar-start
body-end
sidebar-end
header-start body-end header-end
body-start sidebar-start sidebar-end
.
Represents a null (empty) cell token
grid-template-
– 16 52 10.1 10.3 57 57
areas
grid-area – 16 52 10.1 10.3 57 57
Spans
span <integer>
Define how many lines the grid area should extend
If you don’t supply a <integer>, span defaults to 1 (no
-<integers> or 0
Sizing Tracks
Various ways to size row & column tracks
» <length>
» <flex> fr unit
» max-content
» min-content
» fit-content()
» minmax()
» auto (default)
» <percentage>
» subgrid
<length> data type; e.g.:
» 10px
» 10em
» 10rem
» 10vh
More in CSS Typography & CSS Data Types
fr
Grid introduces a new unit: fr, short for fraction of the
free space in the grid container
fr is calculated after any non-flexible items
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 1fr 2fr 1fr;
1fr 1fr 1fr
1fr 2fr 1fr
100 1fr 1fr
px
max-content
Largest content in a grid item determines the size of
the track
Similar to white-space: nowrap
No good use cases (prove us wrong!) — it’s the W3C
being completionist again
min-content
Track becomes as small as it can be to accommodate
the width of the longest word, image, video, fixed-size
<div>, & so on
Smallest content in a grid item determines the size of
the track, forcing all text to wrap
Useful for limiting text to the width of an image or
video, for instance
fit-content(<length>|<percentage>)
Largest content in a grid item determines the size of
the track, but not bigger than (<length>|
<percentage>)
Useful!
In this case, the text is less than
250px, so the grid item is as long
as the text
This text is bigger than 250px, so
it’s wrapped
minmax(min, max)
Defines the size of a track as a minimum to maximum
range
The middle grid item is
250px, which is the
maximum size we set
The middle grid
item will not get
smaller than
100px
auto
Width automatically calculated based on content,
similar to table layout algorithm
You abdicate control when you use auto, so you may get
unexpected results
Note that auto track sizes (and only auto track sizes)
can be stretched by align-content: stretch &
justify-content: stretch (more later)!
The rendering engine
determined those widths, which
may not be what you wanted
<percentage>
Using % with grid-template-columns & grid-
template-rows vastly complicates things because you
have to take grid-gap into account
Do not use <percentage> — use fr instead
subgrid
Tells a child grid to re-use the parent grid’s lines for
rows &/or columns
We’ll discuss this later
Track sizing playground
codepen.io/
websanity/pen/oQLoBL
fr 10 *16 52 10.1 10.3 57 57
-ms-
max-content 10 16 52 10.1 10.3 57 57
-ms-
min-content 10 16 52 10.1 10.3 57 57
-ms-
fit-content() 10 16 51 10.1 10.3 29 57
-ms-
minmax() – 12 52 10.1 10.3 57 80
repeat()
Function
repeat(x, y)
CSS function for defining repeated tracks in a grid
Value for grid-template-columns & grid-template-
rows only
repeat(x, y)
x is how many times to y is a <track-list>; for
repeat y: example:
» <positive-integer> » 1fr
» auto-fill » min-content 1fr
» 100px 1fr 200px
» auto-fit
grid-template-columns: repeat(3, 100px);
3: Number of times to repeat
100px: <track list> to repeat
“Repeat 100px 3 times”
Equivalent to grid-template-columns: 100px 100px
100px;
grid-template-columns: repeat(2, 50px 1fr);
2: Number of times to repeat
50px 1fr: <track list> to repeat
“Repeat 50px 1fr 2 times”
Equivalent to grid-template-columns: 50px 1fr
50px 1fr;
grid-template-columns: repeat(2, 50px 1fr)
100px;
2: Number of times to repeat
50px 1fr: <track list> to repeat
“Repeat 50px 1fr 2 times, then insert 100px”
Equivalent to grid-template-columns: 50px 1fr
50px 1fr 100px;
grid-template-columns: 100px repeat(2, 1fr)
100px;
2: Number of times to repeat
1fr: <track list> to repeat
“Insert 100px, then repeat 1fr 2 times, then insert
100px”
Equivalent to grid-template-columns: 100px 1fr
1fr 100px;
grid-template-columns: repeat(3, minmax(100px,
1fr));
3: Number of times to repeat
minmax(100px, 1fr): <track list> to repeat
“Insert a minimum size of 100px & a max of 1fr, then
repeat 3 times”
Equivalent to grid-template-columns:
minmax(100px, 1fr) minmax(100px, 1fr)
minmax(100px, 1fr);
1fr wide
100px wide
100px wide 😖
auto-fill
Create new tracks to fill the container when there is
enough room
auto-fit
Creates new tracks when there is enough room, but
then resizes tracks that have items so they fit the
container
All columns are 100px
Why are there 3 columns?
All columns are 1fr
Container has 100px of
space, so auto-fill
creates a new track
auto-fit created a new
track also (see the 5?)
but only the 3 tracks
with items are resized
auto-fill
creates 2 extra
tracks
auto-fit created a new
track also (see the 6?)
but only the 3 tracks
with items are resized
auto-fill creates 4 extra tracks
auto-fit
created a new
track also (see
the 8?) but only
the 3 tracks
with items are
resized
Why 8 lines for auto-fit? New tracks
are created, but they don’t have items in
them, so they take up no space & do not
affect the layout
No items, no tracks
auto-fill & auto-fit only create
2 column tracks, but there’s not
enough room with numeric for its
3 column tracks, so it blows out of
the container
Not yet large enough to create 2 ≥ 100px
tracks… & numeric continues to blow
out of the container
Since the grid-gap is 20px, we
need 220–339px to create 2 tracks
repeat() – 16 59* 10.1 10.3 57 80
* repeat(auto-fill, ...) & repeat(auto-fit, ...) still only support 1 repeated column
as of version 72 (March 2020)
Aligning
Within the Grid
Gutters
row-gap
column-gap
gap
December 14, 2017 W3C Candidate Recommendation
for CSS Grid Layout Module Level 1 announced this
change:
“Removed grid-row-gap, grid-column-gap, and grid-
gap properties, replacing with row-gap, column-gap,
and gap which are now defined in CSS Box Alignment.
(Issue 1696)”
All gap properties have to do with setting the minimum
amount of space between rows & columns
row-gap
Defines minimum size of grid gutter between rows
column-gap
Defines minimum size of grid gutter between columns
gap
Defines minimum size of grid gutter between rows &
columns
Shorthand for setting row-gap & column-gap
Values for row-gap, column-gap, & gap
» <length>
» <percentage>: never use this, or you shall sink into a
Stygian madness
All gap properties can accept 1 or 2 values, e.g.:
gap: 1em
Sets value for both row-gap & column-gap
gap: .5em 1em
Sets value for row-gap & then column-gap
No value set for rows, so they
default to 0
gap: 20px sets value for both
row-gap & column-gap
gap: 10px 20px sets value for
row-gap & then column-gap
All gap properties set the size of
the grid’s gutter between tracks
only, not between the container
& the items
💡PRO TIP
All gap properties set the minimum distance between
tracks, however, justify-content & align-content
(covered next) can increase the distance
grid-row-gap – 16 52 10.1 10.3 57 57
row-gap – 16 61 12 12 66 66
grid-column-gap – 16 52 10.1 10.3 57 57
column-gap – 16 61 12 12 66 66
grid-gap – 16 57 10.1 10.3 57 57
gap – 16 66 12 12 66 66
Aligning Grid Tracks
justify-content
align-content
place-content
Grid lines
Block axis
Inline axis
All of the *-content properties in this section align
tracks & gaps in relation to the grid container
Therefore, the container must be larger than the grid
for these to take effect
gap properties set minimum amount of space between
tracks
The *-content properties align tracks within any free
space by specifying how the free space is used
This may result in increasing the gutter size set by gap
justify-content
Sets alignment of grid tracks & gaps along the inline
axis relative to the grid container; i.e., putting space
around columns
This will likely get used more than align-content
(which is for the block axis, & which usually has a fixed
height), because it’s more likely you’ll have viewports
that are wider than the content, giving you free space
Values for justify-content
» normal/stretch: resizes grid items so grid fills full
width of container (default)
» start: aligns grid flush with start edge of container
» end: aligns grid flush with end edge of container
» center: aligns grid in center of container
1
normal
stretch
Resizes tracks so grid fills full width of container
normal is the default, but it is equivalent to stretch in
grid layout
stretch only affects tracks that are sized auto
If a track’s size is not auto, then normal & stretch both
behave like start
Gap
Gap
Gap
Gap
More values for justify-content
» space-between: distributes all free space between
grid columns
» space-around: distributes all free space equally
around each column
» space-evenly: distributes all free space equally
between each column, as well as start & end of
container
2
space-between
Distributes all free space between grid columns, so
there is no free space at the start & end of the container
Gap
space-around
Distributes free space equally around (on either side
of) each column
The amount of space added between each column is
twice that which is added to the start & end of the
container
Gap
space-evenly
Distributes all free space equally between each
column, as well as start & end of container, i.e.:
» start of container & 1st column
» between each column
» between last column & end of container
Gap
✏ SIDE NOTE
Why didn’t you see the Firefox Grid Inspector in the
last series of screenshots?
Because *-content alignment causes very buggy
behavior in Firefox & it doesn’t highlight the grid
properly
align-content
Sets alignment of grid tracks & gaps along the block
axis relative to the grid container
Values & behavior are exactly like justify-content,
but for putting space around rows instead of columns
place-content
Sets alignment of grid tracks & gaps along the block &
inline axes relative to the grid container
Shorthand for align-content & justify-content
place-content can accept 1 or 2 values, e.g.:
place-content: start
Sets value for both align-content & justify-content
place-content: start space-between
Sets value for align-content & then justify-content
align-content – 16 52 10.1 10.3 57 57
justify-content – 16 52 10.1 10.3 57 57
place-content – 79 60 11 11 59 Y
Aligning Grid Items
align-items
justify-items
place-items
align-self
justify-self
place-self
All of the *-items & *-self properties in this section
align grid items in relation to the areas in which they
are placed
Therefore, the area must be larger than the grid item
for these to take effect
Align All Grid Items
justify-items
Aligns all grid items along the inline axis of their areas
Values for justify-items
» normal: acts as either stretch or start (default)
» stretch: stretches grid items to fill their areas but
only if items are sized auto
» start: align grid items flush with inline start edges of
area
» end: align grid items flush with inline end edges of
area
» center: align grid items in inline centers of areas
✏ SIDE NOTE
There are some values — e.g., self-start & self-end
— that are for edge cases that we aren’t going to cover
here
normal
Default value that acts like stretch, unless the flex item
has intrinsic dimensions, in which case it acts like
start
Isn’t CSS fun?
stretch
Stretches grid items to fill their areas but only if items
are sized auto (which is the default), so stretch is what
you’re going to see most of the time when you first
create a grid
If they are sized any other way, stretch behaves like
start
align-items
Aligns all grid items along the block axis of their areas
Values & behavior are exactly like justify-items, but
for affecting things along the block axis instead of inline
Align Individual Grid Items
align-self
Aligns a grid item along the block axis of its area
justify-self
Aligns a grid item along the inline axis of its area
Values for align-self (block) & justify-self
(inline)
» normal: acts as either stretch or start (default)
» stretch: stretches a grid item to fill its area but only
if item is sized auto
» start: align a grid item flush with start edge of area
» end: align a grid item flush with end edge of area
» center: align a grid item in center of area
place-self
Sets alignment of grid item along the block & inline
axes relative to its area
Shorthand for align-self & justify-self
place-self can accept 1 or 2 values, e.g.:
place-self: center
Sets value for both align-self & justify-self
place-self: start center
Sets value for align-self & then justify-self
align-items – 16 52 10.1 10.3 57 57
justify-items – 16 45 10.1 10.3 57 57
align-self 10* 16 52 10.1 10.3 57 57
justify-self – 16 45 10.1 10.3 57 57
place-self ? ? 45 – – 59 59
*Use -ms-grid-column-align
There are 2 ways tracks are created — either by you or
for you
» Explicit: you explicitly define how many rows &
columns there are in the grid (that’s what we’ve
learned until now)
» Implicit: items that don’t fit within the grid’s
explicitly defined rows & columns will cause the
needed rows & columns to be created for you
Implicit Grid
grid-auto-rows
grid-auto-columns
grid-auto-flow
We explicitly created 6 tracks:
3 columns & 3 rows
We added a grid item that
doesn’t fit, so a new implicit
track is created
grid-auto-flow
Specifies 3 important behaviors of grid items:
» the direction in which automatically placed items fill
the grid: row or column?
» the direction in which implicit tracks are created:
rows or columns?
» how automatically placed items are packed
Values for grid-auto-flow
» row: automatically placed items go in rows, & new
implicit tracks are rows (default)
» column: automatically placed items go in columns, &
new implicit tracks are columns
» dense: items attempt to fill in empty areas earlier in
the grid where previous items wouldn’t fit, which may
very well cause items to appear out of order!
You can combine either row or column with dense
» row dense: fill each row using the dense algorithm
(identical to dense, so you’ll never need to use it)
» column dense: fill each column using the dense
algorithm
Why is 10 so short? Because the
default for sizing is auto
Why is 10 so wide? Because the
default for sizing is auto
Sparse packing is the default: each item is placed in
order, & if the item doesn’t fit in an area, it skips ahead
to the next area it does fit, leaving behind empty areas
Dense packing: each item is placed into the next area in
which it will fit, including previous empty areas,
causing items to appear out of order
Sparse packing by row
dense packing by row
Sparse packing by column
dense packing by column
grid-auto-rows
Specifies the size of an implicitly-created grid row
track or pattern of tracks when grid-auto-flow: row
grid-auto-columns
Specifies the size of an implicitly-created grid column
track or pattern of tracks when grid-auto-flow:
column
Values for grid-auto-rows & grid-auto-columns
» <length>
» <percentage>
» <flex> fr unit
» max-content
» min-content
» minmax()
» auto
repeat() is missing because values auto repeat, as
you will see
Note that you cannot combine grid-auto-rows &
grid-auto-columns because only 1 will have an effect
due to grid-auto-flow
Either rows will be created (if grid-auto-flow: row,
which is the default) or columns (if grid-auto-flow:
column)
Implicit tracks are created when
items can’t fit in the grid
Since there are no items, no
implicit rows are created, &
therefore no grid is created
Note that the rows repeat
automatically, without needing
repeat()
Implicit rows are created to
accommodate grid items,
using the sizes we set
grid-auto-
– 16 52 10.1 10.3 57 Y
flow-
grid-auto-
1o* 16 70 10.1 10.3 57 Y
rows-
grid-auto-
columns-
1o* 16 70 10.1 10.3 57 Y
* Uses -ms-grid-rows & -ms-grid-columns
Subgrid
grid-template-rows: subgrid
grid-template-columns: subgrid
Tells a child grid to re-use the parent grid’s lines for
rows &/or columns
subgrid – – 71 – – – –
Techniques
Grid items can also be flex
containers
Tools
Grid Bugs
Thank you!
[email protected]
www.granneman.com
ChainsawOnATireSwing.com
@scottgranneman
[email protected]
websanity.com
CSS Grid Layout
Robust Layout Using Rows r Columns
R. Scott Granneman r Jans Carton
© 2014 R. Scott Granneman
Last updated 2020-07-17
You are free to use this work, with certain restrictions.
3.3 For full licensing information, please see the last slide/page.
Changelog
2020-07-17 3.3: Updated screenshots for max-content
2020-07-16 3.2: Added details re: grid-template-
columns & grid-template-rows; added span; changed
subtitle; added compatibility tables where missing;
added source links where missing; updated lots more
Changelog
2020-05-02 3.1: Added new section on Inspecting
Grids
2018-10-19 3.0: Moved grid slides out of CSS Layout &
into its own slide deck; updated grid screenshot from
Can I Use; completely re-organized the entire slide deck
& added tons of new content
Licensing of this work
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
You are free to:
» Share — copy and redistribute the material in any medium or format
» Adapt — remix, transform, and build upon the material for any purpose, even commercially
Under the following terms:
Attribution. You must give appropriate credit, provide a link to the license, and indicate if changes were made.
You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your
use. Give credit to:
Scott Granneman • www.granneman.com • [email protected]
Share Alike. If you remix, transform, or build upon the material, you must distribute your contributions under
the same license as the original.
No additional restrictions. You may not apply legal terms or technological measures that legally restrict others
from doing anything the license permits.