Positioning Tutorial
Many beginners have trouble understanding how to position elements and create layouts in CSS. So I wrote this guide to teach you the most important stuff!
Hello mobile user! Due to the large amount of layout previews on this page I highly recommend viewing it on a desktop instead!
If you have questions or feedback regarding the tutorial, please use the comment section at the end of the page! Don't be shy; I know it's frustrating when you're stuck, and I'd love to help.
The Box Model (box-sizing
)
The "box model" describes how paddings and borders work in CSS.
By default, paddings and borders are added to any width/height you define:
height: 150px;
width: 300px;
border: 5px solid currentColor;
padding: 10px;
Default.
Actual height: 150px + left padding (10px) + right padding (10px) + left border (5px) + right border (5px) = 180px
Actual width: 300px + left padding (10px) + right padding (10px) + left border (5px) + right border (5px) = 330px
With box-sizing: border-box
you can change this behaviour. The paddings and borders will now be included in the width/height defined:
height: 150px;
width: 300px;
border: 5px solid currentColor;
padding: 10px;
box-sizing: border-box;
Actual height: 150px
Actual width: 300px
If you prefer this behaviour in general you can give every element on your page
box-sizing: border-box
by using* { box-sizing: border-box; }
I highly recommend doing this.
The display
property
The display
property is one of the most important CSS properties, so it's important to understand it well. It can take these values:
display: block
: the element is full-width by default and takes up a new line, and can be given a fixed width and heightdisplay: inline
: the element does not take up a new line (instead, it flows with the text), and cannot be given a fixed width and heightdisplay: inline-block
: same as inline, but it's possible to set a size, and margins/paddings work as expected, and you can give it a fixed width and height.display: flex
: Flexbox (see later)display: inline-flex
: Flexbox (see later) which does not take up a new linedisplay: grid
: Grid layout (see later)
Defaults
All HTML elements have either display: block
or display: inline
as a default setting.
Most elements, like <div>
, <p>
, <h1>
are display: block
by default. After them, there's an automatic line break. That's why - by default - multiple <div>
s are shown underneath one another, not next to each other.
Some elements, like <span>
, <img>
, <b>
, <i>
, <u>
are display: inline
by default, which means they flow with the text. This is why you can make a word in a line bold without creating a line break. Unfortunately, you can't set a fixed size to display: inline
elements. But you can make them display: inline-block
instead and then you can, and margins and paddings will work as expected.
Examples
In each of the following examples I added a box in the middle of the text. The boxes have the following styling additionally to the display
property:
height: 60px;
padding: 10px;
margin: 10px;
Notice how display: inline
does have the padding and margin, but it's not quite behaving as expected: The top and bottom marings are ignored by other elements. The height
we set is ignored completly (and width
would have been ignored too).
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: blockDolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: inline Dolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: inline-block Dolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
Show more examples
Here are the rest of the possible values. Note that they are - so far - not much different from the ones above. Flexbox and Grid mostly become interesting once your element includes multiple elements inside of it. More to that later.
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: flex Dolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: inline-flex Dolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
Lorem ipsum, dolor sit amet consectetur adipisicing elit. display: grid Dolores corporis, tempore incidunt sit optio facilis, quae aliquam non odio, debitis mollitia nihil culpa voluptatum odit voluptate voluptatem cupiditate sed suscipit!
I never use the
display: inline
rule. In 99% of cases, you're better off usingdisplay: inline-block
instead. But it's important to know thatdisplay: inline
exists because it is the default styling of some elements, as I mentioned before.
The position
property
The position
property is important to understand when using the properties top
, bottom
, left
and/or right
to set an element's positon.
It can take the following values:
position: static
(Default, does nothing)position: relative
: sets the element's position relative to itselfposition: absolute
: sets the element's position relative to the closest positioned elementposition: fixed
: sets the element's position relative to the browser windowposition: sticky
: Like fixed, but "sticks" to the top of the screen when you try to scroll past it. Not used much these days, because behaviour such as this is usually created using JavaScript
top
, bottom
, left
, right
You can use top
, bottom
, left
, right
to set the position of an element. What exactly it does depends on the value of the positon
property, as I just described.
These properties only work on positioned elements. (You will learn about this in a second.)
As a unit you can use px (Pixels) or % (percent) or vh (percent of browser height) or vw (percent of browser width), or any other distance unit (such as em).
Examples:
.element {
top: 50px;
left: 50px;
}
.element {
top: 50%;
left: 50%;
}
"Positioned" Elements
When you hear "positioned element" it means any element that has any position value other than static
. So elements with position: relative
or position: absolute
or position: fixed
, for example, are "positioned".
By default, all elements have position: static
and are therefore not positioned.
Whenever you want to use
position: absolute
you have to make sure that one of its wrappers is positioned (= e.g. hasposition: relative
). Otherwise it will not work!
Here is a very common example of absolute positioning:
<div class="container">
<div class="element">Element</div>
</div>
.container {
display: relative;
}
.element {
display: absolute;
left: 50%;
top: 50%;
}
position: relative;
position: absolute;
Notice that the left side of the inner element is at 50% of the outer one, and the top side of the inner element is at 50% of the outer one. Therefore, using 50% is not the same centering as an element. We will cover how to center an element later in the this tutorial.
Examples
To illustrate the different values for the position
property visually, here are some examples:
(no top/bottom/left/right)
bottom: 20px;
right: 20px;
position: relative
, otherwise this would not work!)bottom: 20px;
right: 20px;
bottom: 20px;
right: 20px;
(For an example for position: sticky
click here.)
Transforming Elements (transform
)
The transform
property can do a lot of stuff, like repositioning ("translating"), resizing ("scaling"), rotating and mirroring an element.
Some examples:
transform: scale(1.5);
transform: rotate(90deg);
transform: translate(10px);
transform: translate(10px, 10px);
transform: translateX(10px);
transform: skew(10deg, 10deg);
You can use multiple transforms at once by writing them next to each other, seperated by a space. Example: transform: translate(15px, 15px) scale(1.2) rotate(5deg);
For a full list of all possible values go here.
transform
only changes the appearance of an element (e.g. it's apparent size, font size and position), but not the actual space it takes up on your page (or actual font size, etc)!You can see an example of this below: In the last box, notice how the element overflows its container even though only the size and rotation was changed and not its position.
Therefore, in most cases, you should only use transform for effects and decoration, not for the basic positioning of the elements.
Transformed elements may appear slightly blurry in some browsers and resolutions. There's nothing you can do about that.
Values
The transforms always have parentheses ()
in which you add the values.
Some transforms (like scale and rotate) only have one value. For Example: Scale has a percentage (written as a number, e.g. 1
= 100%, 0.5
= 50%, and so on). Rotate uses degrees (deg
).
Other transforms, such as translate, have two values: one for X (horizontal: left to right) and the second for Y (vertical: top to bottom). For example, translate(5px, 10px)
moves an element 5px to the right (= horizontal) and 10px down (= vertical). You can use negative values to move an element to the left or up.
If you only want to change X or Y, you can also use a shortcut like so: translateX(5px)
or translateY(10px)
.
Note that translate(5px)
(without a second value) is the same as translateX(5px)
.
When you use %
in translate
, it refers to the element's own width/height! For example translate(50%)
moves the element half of its own width to the right.
Examples
Default:
Repositioning ("Translating"):
Resizing ("Scaling"): (This still has the same font size as the other examples!)
Rotating:
Mirroring: (this works by using transform: scaleX(-1)
)
Combination of multiple transforms:
Stack Order (z-index
)
If you have two elements on the same position with one "in front of" the other (which happens a lot when you use position: absolute
or position: fixed
you might have to define the stack order of the elements so that the correct one is in the "front".
We can do this by defining a z-index, e.g. z-index: 1;
z-index only works on positioned elements (= elements that have a positon value other than the default, so either
position: relative
orposition: absolute
orposition: fixed
).
A higher z-index means that the element will be shown further in the front.
The stack order of elements is:
- Of the elements with a z-index, the one with the highest one
- All other elements with a z-index, ordered by how high it is
- Lastly, all elements without a z-index
If two elements have the same z-index (or none at all) the last element will be shown the furthest in the front.
By default the last element in the furthest in front:
(no z-index)
(no z-index)
(no z-index)
We can overwrite this by giving an element (in this example the first one) z-index: 1
:
(
z-index: 1
)(no z-index)
(no z-index)
In this example the first two elements have the same z-index (1). Therefore the last element (which has a z-index) is shown in front:
(
z-index: 1
)(
z-index: 1
)(no z-index)
Obviously, if an element has a higher z-index than another one, it is shown in the front:
(
z-index: 1
)(
z-index: 1
)(
z-index: 2
)You will often see people use
z-index: 99999;
to make sure that that element will always be shown on the very front.This is often not necessary: As you can see in the examples above, often
z-index: 1;
or another small number already does the trick!
How to Center Elements
Horizontal
To horizontally center the content of an element you can simply use text-align: center
:
And yes, this works with images and other inline
(or inline-block
) elements too:
To horizontally center elements themselves you can usemargin-left: auto; margin-right: auto;
(short version: margin: 0 auto;
).
This only works for block elements (= display: block
) with a fixed width (e.g. width: 300px;
)!
width: 300px;
margin-left: auto;
margin-right: auto;
Vertical
One way to vertically center an element is to use absolute positioning with top: 50%
and transform: translateY(-50%)
.
(Don't forget that the container element needs to have position: relative
for your absolute positioning to work!)
top: 50%;
transform: translateY(-50%);
Please explain !?
This works because top: 50%
sets the top edge of the element into the vertical center, and transform: translateY(-50%)
moves the element up half its own height.
To demonstrate, this is what it would look like without transform: translateY(-50%)
:
top: 50%;
(No transform)
In-Text
If you have an inline element inside of text you can use vertical-align: middle
to center it vertically. Instead of middle
you could also try top
or bottom
; I recommend trying all values and seeing which one looks best. Often (but not always) the default (basline
) actually looks the most centered, so you don't have to do anything at all.
Text Text Text Text. This is vertical-align: baseline
(default)
Text Text Text Text. This is vertical-align: middle
Text Text Text Text. This is vertical-align: top
Text Text Text Text. This is vertical-align: bottom
Centering with Flexbox
The easiest and fastest way to center an element both horizontally and vertically is to use Flexbox. (I do this literally all the time!) I will explain Flexbox in detail in a moment; For now all you need to know is 3 magic lines.
These lines must be applied to the outer element, not the inner one! The inner element does not need any styling.
.container {
display: flex;
justify-content: center;
align-items: center;
}
.element {
}
To understand why this works, read the next section (CSS Flexbox)! But, in short: The first line defines the container as a flex box, the second horizontally centers its content, and the third line vertically centers its content.
CSS Flexbox (display: flex
)
If you give a container element display: flex
the behaviour of all its children (= elements in it) will change.
Let's look at some examples. (In all the examples below the inner elements have a bit of padding and margin, but otherwise no styling concerning size or position.)
This is what it would look like without Flexbox: (The boxes are all full-width because they are div
s, which are display: block
by default.)
Once we give the wrapper element display: flex
things change:
We can add flex-direction: row-reverse
to reverse the order:
justify-content
We use justify-content
to define the position of the elements along the main axis (in this case horizontally).
By default, it's justify-content: flex-start
, which does what it says: The elements are at the start:
We can change this to justify-content: flex-end
:
To center the elements, we can use justify-content: center
:
For even spacing, we can use justify-content: space-around
:
...or justify-content: space-evenly
:
...or justify-content: space-between
:
align-items
We use align-items
to define the position of the elements along the other axis (in this case vertically).
Do not confuse
align-items
withalign-content
, which does something else!
The default is align-items: stretch
, which stretches the items to fill the height of the container. (If your container has an automatic height you won't notice this at all.):
We can change this to align-items: flex-start
:
or align-items: flex-end
:
And centering is just as easy too: align-items: center
:
... In combination with justify-content: center
this will center our elements along both axes:
flex-direction: column
To change the direction of a flexbox to vertical, use flex-direction: column
:
(The boxes are full-width here because the default value for align-items
(which controls the positiong along the second axis) is stretch
.)
The main axis is now vertical, not horizontal.
That means we change the horizontal alignment with
align-items
, notjustify-content
.
And we change the vertical alignment withjustify-content
, notalign-items
.
Using align-items: flex-start
:
or align-items: center
:
To reverse, we use flex-direction: column-reverse
:
flex-wrap: wrap
Let's imagine our elements don't all fit in our container.
By default, the elements shrink as much as they can: (These items all have a width of 50px, but shrink to try their best to fit into their container)
If we don't want that to happen we can give each of the items (not the wrapper) flex-shrink: 0
:
The widths are correct now, but it's overflowing! What to do?
We'll use flex-wrap: wrap
(on the wrapper)! (We don't need to use flex-shrink: 0
anymore.) The elements that don't fit in the container overflow into the next line:
flex-wrap
works with flex-direction: column
too:
To stop the default stretch, we'll use align-items: flex-start
again:
We can add align-content: flex-start
(notice that it's align-content now, not align-items!) to keep the items closer together:
flex-shrink
and flex-grow
We've already seen one way to style the items themselves: flex-shrink
, which controls whether an item is allowed to or "shrink" to fit the wrapper. The default value is 1
, which means "Yes, this element will try to shrink to fit the container." We can set it to 0
to stop an item from shrinking.
Here's an example with the 3rd element having flex-shrink: 0
:
There's also flex-grow
you can use to allow items to "grow" to fill the space in a container. The default is 0
, which means by default items do not grow. We can set it to 1
to allow growing.
Without using flex-grow
our container would look like this:
Here's an example with the 3rd element having flex-grow: 1
:
Values bigger than 1 can be used to define the importance of shrinking/growing of elements.
In this example, the 3rd element has flex-grow: 1
and the 4th element has flex-grow: 2
, which means that the 4th element will grow more than the 3rd:
There's also flex-basis
, which sets the inital size of an item (in px or %). You won't need this a lot. Go here to read about it.
A shortcut for flex-grow
+ flex-shrink
+ flex-basis
(in this order) is flex
.
For example, flex: 0 1 5px;
means: flex-grow: 0
+ flex-shrink: 1
+ flex-basis: 5px
.
CSS Grid (display: grid
)
By using display: grid
you can easily create grid-based layouts.
Let's look at an example:
(remaining width)
<div class="container">
<header>Header</header>
<aside>Sidebar</aside>
<main>Main Content</main>
<footer>Footer</footer>
</div>
.container {
display: grid;
grid-gap: 10px;
grid-template:
"header header"
"sidebar main"
"footer footer"
/ 100px 1fr;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
Now, the CSS code might look confusing, so let's go through it step-by-step:
- First, give your wrapper
display: grid
to use a grid layout. - We use
grid-gap: 10px
, which is a great way to define the margins between our elements. - Then we will define the layout with
grid-template
. This property takes two values, seperated by a slash (/
):- The first value is your template, in which you define so-called grid areas. You can give them any name you like. In this example I chose header, sidebar, main and footer.
Every row of your layout is in quotation marks (""
), seperated by a space or line break. In each row you define each column of your layout, seperated by a space.
Note that you can use one grid area multiple times if it spans multiple columns or rows. (In this example header and footer both span two columns.) - The second value is a list of column widths, e.g.
100px 1fr
which would make the first column100px
wide and the second column1fr
(= one fraction) of the remaining width. Since we only use 1 fraction in total that 1 fraction is 100% of the remaining width.
- The first value is your template, in which you define so-called grid areas. You can give them any name you like. In this example I chose header, sidebar, main and footer.
- Finally, for each of the wrapper's child elements (our header, sidebar, main content, and footer) we must define which "grid area" (of those defined by us in the
grid-template
rule) it belongs to.Make sure not to use quotation marks (") when using the
grid-area
rules. It won't work.Correct:
grid-area: blah;
Incorrect:grid-area: "blah";
And that's it! You can set your elements' heights like you usually would.
Let's look at another example.
(2/3 of width)
This time, we're using different names for our grid areas, but the main difference is our layout. By changing the grid-template
we have created a different layout, one in which our sidebar spans two rows.
.container {
display: grid;
grid-template:
"myHeader myHeader"
"mySidebar myMainContent"
"mySidebar myFooter"
/ 1fr 2fr;
grid-gap: 10px;
}
header { grid-area: myHeader; }
aside { grid-area: mySidebar; }
main { grid-area: myMainContent; }
footer { grid-area: myFooter; }
We also changed our column widths to 1fr 2fr
. Remember, fr
means fraction (of the remaining width). In our example we have 3 fractions in total (1fr + 2fr = 3), which means that 1fr
is one-third of the width (1/3), and 2fr
is two-thirds of the width (2/3).
If we wanted the sidebar to take up a bit less space we could use a higher total of fractions, e.g. 1fr 3fr
. The total is 4, so 1fr
is one-quarter (1/4) and 3fr
is three-quartes (3/4):
(3/4 of width)
Mobile Responsiveness
We can easily make our layout mobile responsive by changing the grid-template
rule for smaller screens. I highly recommend using only a 1-column layout for mobile, otherwise the columns are horribly small. (Because we only have one column we can also just leave out the column width information.)
@media (max-width: 800px) {
.container {
grid-template:
"myHeader"
"mySidebar"
"myMainContent"
"myFooter";
}
}
On mobile, our layout would now look like this:
In an example such as this you might also want to hide your sidebar on mobile:
@media (max-width: 800px) {
aside {
display: none;
}
}
Scrollboxes (overflow
)
If you want to create a scrolling box, give your element a fixed height
or max-height
and overflow-y: auto
.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quaerat cupiditate mollitia veniam officiis. Repellendus doloribus consectetur numquam sint quo, dolorem itaque officia provident illum tempore assumenda sunt ratione reprehenderit.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quaerat cupiditate mollitia veniam officiis. Repellendus doloribus consectetur numquam sint quo, dolorem itaque officia provident illum tempore assumenda sunt ratione reprehenderit.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quaerat cupiditate mollitia veniam officiis. Repellendus doloribus consectetur numquam sint quo, dolorem itaque officia provident illum tempore assumenda sunt ratione reprehenderit.
Btw, You can do the same thing but horizontally with a fixed width
or max-width
and overflow-x: auto
:
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quaerat cupiditate mollitia veniam officiis. Repellendus doloribus consectetur numquam sint quo, dolorem itaque officia provident illum tempore assumenda sunt ratione reprehenderit.
(In this example I gave the container display: flex
and the inner element flex-shrink: 0
to stop the text from breaking automatically.)
Working with Images
By default, elements stretch automatically to fit the size of their content, so images aren't much of a problem.
But imagine we have a container with a fixed width and/or height, and an image inside it. By default, the image won't fit:
(That's me by the way, hello!!)
We could add overflow: hidden
to hide the "overflowing" parts:
... but that's still not ideal.
The trick to get the width right is to give the image width: 100%
and height: auto
. This is what we get:
If your container had automatic height this would be enough, but in our example we still have vertical overflow! (Even with overflow: hidden
it would still be noticable!)
So, clearly what we need to do is give the image height: 100%
, right? Let's see:
Okay, that fits smugly into the container, but the image is horribly stretched! We can fix this by adding object-fit: contain
:
...or object-fit: cover
, if you're okay with parts of the image being cropped off:
You can change the image crop's position by defining object-position
. For example, object-position: top
will focus on the top part of the image:
This is the code we ended up with:
.container {
width: 200px;
height: 150px;
padding: 10px;
}
.container img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top;
}
If you ever see an annoying little empty space under an image even though you didn't define a margin there, try giving the image element
display: block
. That often gets rid of that unwanted space.(Don't ask me why this happens... I have no clue lol.)
Example: Building an Image Gallery
Let's combine (almost) everything we've learned by creating an image gallery with 10 images. There should be 4 images per row, or 2 images per row on mobile. On hover, the images should zoom in and rotate a bit and show a caption.
At the end, it will look like this:
Show Full Code
You don't need to read all of this right now, we're going to build up to it step-by-step!
/* Wrapper */
.example-image-gallery {
display: flex;
flex-wrap: wrap;
}
/* Items */
.example-image-gallery div {
box-sizing: border-box;
width: calc(25% - 10px);
margin: 5px;
border: 5px solid;
overflow: hidden;
position: relative;
}
/* Images */
.example-image-gallery div img {
transition: transform 0.5s ease;
width: 100%;
height: 100%;
object-fit: cover;
}
/* Captions */
.example-image-gallery div span {
position: absolute;
bottom: 15px;
left: 0;
text-align: center;
width: 100%;
box-sizing: border-box;
background: white;
color: black;
padding: 5px 10px;
font-size: 20px;
opacity: 0;
transform: translateY(100px);
transition: transform 0.4s ease, opacity 0.5s ease;
}
/* Images on Hover */
.example-image-gallery div:hover img {
transform: scale(1.35) rotate(10deg);
}
/* Captions on Hover */
.example-image-gallery div:hover span {
opacity: 1;
transform: none;
}
/* Mobile */
@media (max-width: 800px) {
.example-image-gallery div {
width: calc(50% - 10px);
}
}
Step 1: The HTML
The HTML for this project is very straightforward.
All our items are a simple div
with an image (img
) and a caption (span
).
<div class="example-image-gallery">
<div> <img src="./img/example1.jpg" /> <span>Image 1</span> </div>
<div> <img src="./img/example2.jpg" /> <span>Image 2</span> </div>
<div> <img src="./img/example3.jpg" /> <span>Image 3</span> </div>
<div> <img src="./img/example4.jpg" /> <span>Image 4</span> </div>
<div> <img src="./img/example5.jpg" /> <span>Image 5</span> </div>
<div> <img src="./img/example6.jpg" /> <span>Image 6</span> </div>
<div> <img src="./img/example7.jpg" /> <span>Image 7</span> </div>
<div> <img src="./img/example8.jpg" /> <span>Image 8</span> </div>
<div> <img src="./img/example9.jpg" /> <span>Image 9</span> </div>
<div> <img src="./img/example10.jpg" /> <span>Image 10</span> </div>
</div>
Step 2: Item Sizing
We're going to start our CSS with a simple code to make sure the images aren't bigger than they should be. We will give our items (the div
s) a width of 25% because we want 4 images per row. I will also add a margin and border. To make sure that the images fill up their wrapper and don't overflow we use the object-fit: cover
trick we learned earlier.
.example-image-gallery div {
width: 25%;
margin: 5px;
border: 5px solid;
}
.example-image-gallery div img {
width: 100%;
height: 100%;
object-fit: cover;
}
Now, our items should look like this:
Step 3: Flexbox
Right now, all our items are underneath one another instead of next to each other.
We will use flexbox to get them to display in a row, and automatically overflow to the next line.
.example-image-gallery {
display: flex;
flex-wrap: wrap;
}
Almost there! One problem: We have 3 items in a line instead of the 4 we wanted.
This is because we defined the width of each item as 25%, but we also have a margin of 5px and a border of 5px on the left and right.
First, we'll add box-sizing: border-box
to our items so that the borders (and padding, if we had any) count towards the width. That takes care of the borders, but the margins are still a problem.
So we need to set the width of each item to 25% minus 5px (left margin) minus 5px (right margin). We can do this using calc()
: width: calc(25% - 5px - 5px)
, or just width: calc(25% - 10px)
.
While we're at it, we will also fix the width for mobile browsers. On smaller screens everything will be a bit smaller, so we only want to show 2 images per row instead of 4. This means our width will be 50% (minus margins) instead of 25% (minus margins):
The code:
/* Items */
.example-image-gallery div {
box-sizing: border-box;
width: calc(25% - 10px);
}
/* Mobile */
@media (max-width: 800px) {
.example-image-gallery div {
width: calc(50% - 10px);
}
}
Now our gallery is already looking pretty good:
Step 4: Captions
It's time to style our captions. We want them to be "in front of" the images, which means we have to use absolute positioning (position: absolute
) and place the caption where we want (bottom: 15px
and left: 0
). We'll also add some basic styling, like width: 100%
. To make sure the width is correct, we add box-sizing: border-box
again.
Remember that, because we're using absolute positioning, the parent element needs to be "positioned", so we will give the item position: relative
to take care of that.
This is the code we added:
/* Items */
.example-image-gallery div {
position: relative;
}
/* Captions */
.example-image-gallery div span {
position: absolute;
bottom: 15px;
left: 0;
width: 100%;
box-sizing: border-box;
background: white;
color: black;
text-align: center;
padding: 5px 10px;
font-size: 20px;
}
Here's what it looks like:
We could be done now, but I want to show you how to add some hover effects!
Step 5: Captions on Hover
First, we want the caption to show on hover only. We can do this by giving the captions opacity: 0
by default and opacity: 1
on hover.
To add some movement I will also give the captions transform: translateY(100px)
by default and reset that to transform: none
on hover. This means that the caption will be 100px further down when the element is not being hovered over, which essentially means that it moves up as we hover on it.
I'm adding a transition
(for both the transform and the opacity) to make the effect smoother.
transition
rules should always be added to the normal CSS rules, not the on-hover rules (:hover
), otherwise it will only work when the mouse moves in but not out.
Here's the code we're adding:
/* Captions */
.example-image-gallery div span {
opacity: 0;
transform: translateY(100px);
transition: transform 0.4s ease, opacity 0.5s ease;
}
/* Captions on Hover */
.example-image-gallery div:hover span {
opacity: 1;
transform: none;
}
Hover over the images to preview the effect:
For now, you might see the captions being visible outside of the frames as they move up. We will fix this in the next step.
Step 6: Image Hover Effects
Finally, we're gonna add some image effects on hover. We want the images to become larger and rotate a bit, so we can use something like transform: scale(1.35) rotate(10deg)
. We're adding that to the images, not the whole items, otherwise our captions would move too.
Again, we're adding a transition (not just on hover!) to make the movement smoother.
/* Images */
.example-image-gallery div img {
transition: transform 0.5s ease;
}
/* Images on Hover */
.example-image-gallery div:hover img {
transform: scale(1.35) rotate(10deg);
}
Now it looks like this:
Oops! Our images are moving outside of their frames! We can add overflow: hidden;
to the items to stop that from happening. This also fixes the problem that our captions show up slightly outside of the frames.
/* Items */
.example-image-gallery div {
overflow: hidden;
}
Now we're done:
Looks neat, doesn't it?
Congrats! This is all I can teach you for now. I hope this tutorial helped you a bit!
I spend hours of my free time writing these tutorials that I publish for free. If you'd like to say thanks, please share this tutorial with others and/or buy me a coffee!
Comments
Leave your questions, problems, suggestions, requests and thanks here!
To share very long code or error messages with me, please upload it to pastebin (or a similar site) and include the link. This is to make sure you don't hit the max character limit on comments.