From 5f68181f5322d3b9ca5020d51bcc7ef4019cbf44 Mon Sep 17 00:00:00 2001 From: estelle Date: Mon, 17 Jun 2024 22:16:21 -0700 Subject: [PATCH] CSS maintenance: Learn flexbox --- .../learn/css/css_layout/flexbox/index.md | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/files/en-us/learn/css/css_layout/flexbox/index.md b/files/en-us/learn/css/css_layout/flexbox/index.md index 72cd213f7cedf07..efcad7d8ab4ede0 100644 --- a/files/en-us/learn/css/css_layout/flexbox/index.md +++ b/files/en-us/learn/css/css_layout/flexbox/index.md @@ -31,15 +31,13 @@ page-type: learn-module-chapter ## Why Flexbox? -For a long time, the only reliable cross-browser compatible tools available for creating CSS layouts were features like [floats](/en-US/docs/Learn/CSS/CSS_layout/Floats) and [positioning](/en-US/docs/Learn/CSS/CSS_layout/Positioning). These work, but in some ways they're also limiting and frustrating. +CSS flexible box layout enables you to: -The following simple layout designs are either difficult or impossible to achieve with such tools in any kind of convenient, flexible way: +- Vertically center a block of content inside its parent. +- Make all the children of a container take up an equal amount of the available width/height, regardless of how much width/height is available. +- Make all columns in a multiple-column layout adopt the same height even if they contain a different amount of content. -- Vertically centering a block of content inside its parent. -- Making all the children of a container take up an equal amount of the available width/height, regardless of how much width/height is available. -- Making all columns in a multiple-column layout adopt the same height even if they contain a different amount of content. - -As you'll see in subsequent sections, flexbox makes a lot of layout tasks much easier. Let's dig in! +Flexbox features may be the perfect solution for your one dimensional layout needs. Let's dig in and find out! ## Introducing a simple example @@ -79,8 +77,8 @@ When elements are laid out as flex items, they are laid out along two axes: ![Three flex items in a left-to-right language are laid out side-by-side in a flex container. The main axis — the axis of the flex container in the direction in which the flex items are laid out — is horizontal. The ends of the axis are main-start and main-end and are on the left and right respectively. The cross axis is vertical; perpendicular to the main axis. The cross-start and cross-end are at the top and bottom respectively. The length of the flex item along the main axis, in this case, the width, is called the main size, and the length of the flex item along the cross axis, in this case, the height, is called the cross size.](flex_terms.png) -- The **main axis** is the axis running in the direction the flex items are laid out in (for example, as a row across the page, or a column down the page.) The start and end of this axis are called the **main start** and **main end**. -- The **cross axis** is the axis running perpendicular to the direction the flex items are laid out in. The start and end of this axis are called the **cross start** and **cross end**. +- The **main axis** is the axis running in the direction the flex items are laid out in (for example, as a row across the page, or a column down the page.) The start and end of this axis are called the **main start** and **main end**. The length from the main-start edge to the main-end edge is the **main size**. +- The **cross axis** is the axis running perpendicular to the direction the flex items are laid out in. The start and end of this axis are called the **cross start** and **cross end**. The length from the cross-start edge to the cross-end edge is the **cross size**. - The parent element that has `display: flex` set on it (the {{htmlelement("section")}} in our example) is called the **flex container**. - The items laid out as flexible boxes inside the flex container are called **flex items** (the {{htmlelement("article")}} elements in our example). @@ -104,9 +102,9 @@ You'll see that this puts the items back in a column layout, much like they were One issue that arises when you have a fixed width or height in your layout is that eventually your flexbox children will overflow their container, breaking the layout. Have a look at our [flexbox-wrap0.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flexbox-wrap0.html) example and try [viewing it live](https://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox-wrap0.html) (take a local copy of this file now if you want to follow along with this example): -![The Sample flexbox example has all the flex items laid out in a single row of the flex container. The eighth flex item overflows the browser window, and the page has visible horizontal and vertical scroll bars as it cannot be accommodated within the width of the window as the previous seven flex items have taken the space available within the viewport. By default, the Browser tries to place all the flex items in a single row if the flex-direction is set to row or a single column if the flex-direction is set to column.](flexbox-example3.png) +![The Sample flexbox example has all the flex items laid out in a single row of the flex container. The eighth flex item overflows the browser window, and the page has visible horizontal and vertical scroll bars as it cannot be accommodated within the width of the window as the previous seven flex items have taken the space available within the viewport.](flexbox-example3.png) -Here we see that the children are indeed breaking out of their container. One way in which you can fix this is to add the following declaration to your {{htmlelement("section")}} rule: +Here we see that the children are indeed breaking out of their container. By default, the browser tries to place all the flex items in a single row if the `flex-direction` is set to `row` or a single column if the `flex-direction` is set to `column`. One way in which you can fix this is to add the following declaration to your {{htmlelement("section")}} rule: ```css flex-wrap: wrap; @@ -122,7 +120,7 @@ Try this now. You'll see that the layout looks much better with this included: ![Flex items are laid out in multiple rows in the flex container. The flex-wrap property is set to 'wrap' in the flex container which displays the flex items in a new row if the flex items in the previous row overflow outside the flexbox container. Each flex item is given a width of 200 pixels. All the items are stretched to be the same height, as tall as the flex item with the most content.](flexbox-example4.png) -We now have multiple rows. Each row has as many flexbox children fitted into it as is sensible. Any overflow is moved down to the next line. The `flex: 200px` declaration set on the articles means that each will be at least 200px wide. We'll discuss this property in more detail later on. You might also notice that the last few children on the last row are each made wider so that the entire row is still filled. +We now have multiple rows. Each row has as many flexbox children fitted into it as is sensible. Any overflow is moved down to the next line. The `flex: 200px` declaration set on the articles means that each will be at least `200px` wide. We'll discuss this property in more detail later on. You might also notice that the last few children on the last row are each made wider so that the entire row is still filled. But there's more we can do here. First of all, try changing your {{cssxref("flex-direction")}} property value to `row-reverse`. Now you'll see that you still have your multiple row layout, but it starts from the opposite corner of the browser window and flows in reverse. @@ -143,7 +141,7 @@ flex-flow: row wrap; ## Flexible sizing of flex items -Let's now return to our first example and look at how we can control what proportion of space flex items take up compared to the other flex items. Fire up your local copy of [flexbox0.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flexbox0.html), or take a copy of [flexbox1.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flexbox1.html) as a new starting point ([see it live](https://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox1.html)). +Let's now return to our first example and look at how we can control what proportion of space flex items take up compared to the other flex items. Open your local copy of [flexbox0.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flexbox0.html), or take a copy of [flexbox1.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flexbox1.html) as a new starting point ([see it live](https://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox1.html)). First, add the following rule to the bottom of your CSS: @@ -153,7 +151,7 @@ article { } ``` -This is a unitless proportion value that dictates how much available space along the main axis each flex item will take up compared to other flex items. In this case, we're giving each {{htmlelement("article")}} element the same value (a value of 1), which means they'll all take up an equal amount of the spare space left after properties like padding and margin have been set. This value is proportionally shared among the flex items: giving each flex item a value of 400000 would have exactly the same effect. +This is a unitless proportion value that dictates how much available space along the main axis each flex item will take up compared to other flex items. In this case, we're giving each {{htmlelement("article")}} element the same value (a value of `1`), which means they'll all take up an equal amount of the spare space left after properties like padding and margin have been set. This value is proportionally shared among the flex items: giving each flex item a value of `400000` would have exactly the same effect. Now add the following rule below the previous one: @@ -177,9 +175,11 @@ article:nth-of-type(3) { } ``` -This basically states, "Each flex item will first be given 200px of the available space. After that, the rest of the available space will be shared according to the proportion units." Try refreshing and you'll see a difference in how the space is shared. +This basically states, "Each flex item will first be given `200px` of the available space. After that, the rest of the available space will be shared according to the proportion units." Try refreshing and you'll see a difference in how the space is shared. + +![A flex container with three flex items. The third flex item is slightly larger than the first two.](flexbox-example1.png) -![The Sample flexbox example flex container has three flex items. All the flex items have a minimum width of 200 pixels—set using 'flex'. The value of flex for first two flex items is 1 and for the third item is 2. This splits the remaining space in the flex container into 4 proportion units. One unit is assigned to each of the first two flex items and 2 units are assigned to the third flex item, making the third flex item wider than the other two, which are of the same width.](flexbox-example1.png) +All the flex items have a minimum width of 200 pixels—set using 'flex'. The value of flex for first two flex items is 1 and for the third item is 2. This splits the remaining space in the flex container into 4 proportion units. One unit is assigned to each of the first two flex items and 2 units are assigned to the third flex item, making the third flex item wider than the other two, which are of the same width. The real value of flexbox can be seen in its flexibility/responsiveness. If you resize the browser window or add another {{htmlelement("article")}} element, the layout continues to work just fine. @@ -191,13 +191,13 @@ The real value of flexbox can be seen in its flexibility/responsiveness. If you - A second unitless proportion value, {{cssxref("flex-shrink")}}, which comes into play when the flex items are overflowing their container. This value specifies how much an item will shrink in order to prevent overflow. This is quite an advanced flexbox feature and we won't be covering it any further in this article. - The minimum size value we discussed above. This can be specified separately using the {{cssxref("flex-basis")}} longhand value. -We'd advise against using the longhand flex properties unless you really have to (for example, to override something previously set). They lead to a lot of extra code being written, and they can be somewhat confusing. +We'd advise against using the longhand flex properties unless you really have to (for example, to override something previously set). They lead to a lot of extra code being written and can be somewhat confusing. ## Horizontal and vertical alignment You can also use flexbox features to align flex items along the main or cross axis. Let's explore this by looking at a new example: [flex-align0.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/flex-align0.html) ([see it live also](https://mdn.github.io/learning-area/css/css-layout/flexbox/flex-align0.html)). We're going to turn this into a neat, flexible button/toolbar. At the moment you'll see a horizontal menu bar with some buttons jammed into the top left-hand corner. -![Five buttons with labels Smile, Laugh, Wink, Shrug and Blush are laid out in a row in a flex container. The buttons are jammed into the top left-hand corner that doesn't look neat.](flexbox-example5.png) +![Five buttons are laid out in a row in a flex container. The buttons are jammed into the top left-hand corner that doesn't look neat.](flexbox-example5.png) First, take a local copy of this example. @@ -211,15 +211,15 @@ div { } ``` -![Five buttons with labels Smile, Laugh, Wink, Shrug & Blush are laid out in a row in a flex container. The flex items are positioned at the center of the cross-axis by setting the align-items property to center. The flex items are spaced evenly along the main-axis by setting the justify-content property to space-around.](flexbox_center_space-around.png) +![Five buttons are laid out in a row in a flex container. The flex items are positioned vertically centered and they are evenly spaced out horizontally.](flexbox_center_space-around.png) -Refresh the page and you'll see that the buttons are now nicely centered horizontally and vertically. We've done this via two new properties. +Refresh the page and you'll see that the buttons are now nicely centered horizontally and vertically. We've done this via two new properties. The flex items are positioned at the center of the cross-axis by setting the `align-items` property to `center`. The flex items are spaced evenly along the main-axis by setting the `justify-content` property to `space-around`. -{{cssxref("align-items")}} controls where the flex items sit on the cross axis. +The {{cssxref("align-items")}} property controls where the flex items sit on the cross axis. -- By default, the value is `stretch`, which stretches all flex items to fill the parent in the direction of the cross axis. If the parent doesn't have a fixed height in the cross axis direction, then all flex items will become as tall as the tallest flex item. This is how our first example had columns of equal height by default. +- By default, the value `normal` which behaves as `stretch` in flexbox. This stretches all flex items to fill the parent in the direction of the cross axis. If the parent doesn't have a fixed size in the cross axis direction, then all flex items will become as tall (or wide) as the tallest (or widest) flex item. This is how our first example had columns of equal height by default. - The `center` value that we used in our above code causes the items to maintain their intrinsic dimensions, but be centered along the cross axis. This is why our current example's buttons are centered vertically. -- You can also have values like `flex-start` and `flex-end`, which will align all items at the start and end of the cross axis respectively. See {{cssxref("align-items")}} for the full details. +- You can also have values like `flex-start`, `self-start` or `start` and `flex-end`, `self-end` or `end`, which will align all items at the start and end of the cross axis respectively. The `baseline` values will line up the flex items by their baseline; basically the bottom of each flex items first line of text will be lined up with the bottom of the first line of the element with the greatest distance between the cross start and that baseline. See {{cssxref("align-items")}} for the full details. You can override the {{cssxref("align-items")}} behavior for individual flex items by applying the {{cssxref("align-self")}} property to them. For example, try adding the following to your CSS: @@ -229,14 +229,15 @@ button:first-child { } ``` -![Five buttons with labels Smile, Laugh, Wink, Shrug & Blush are laid out in a row in a flex container. All the flex items except the first one are positioned at the center of the cross-axis, or vertically centered, by setting the align-items property to center. The first item is flush against the bottom of the flex container, at the end of the cross-axis, with the align-self property set to flex-end. The flex items are spaced evenly along the main-axis, or width, of the container.](flexbox_first-child_flex-end.png) +![Five buttons are laid out in a row in a flex container. All the flex items except the first one are positioned at the center of the cross-axis, or vertically centered. The first item is flush against the bottom of the flex container, at the end of the cross-axis The flex items are spaced evenly along the main-axis, or width, of the container.](flexbox_first-child_flex-end.png) Have a look at what effect this has and remove it again when you've finished. {{cssxref("justify-content")}} controls where the flex items sit on the main axis. -- The default value is `flex-start`, which makes all the items sit at the start of the main axis. -- You can use `flex-end` to make them sit at the end. +- The default value is `normal`, which behaves as `start`, which makes all the items sit at the start of the main axis. +- You can use `end` or `flex-end` to make them sit at the end. +- The `left` and `right` values behave as `start` or `end` depending on the writing mode direction. - `center` is also a value for `justify-content`. It'll make the flex items sit in the center of the main axis. - The value we've used above, `space-around`, is useful — it distributes all the items evenly along the main axis with a bit of space left at either end. - There is another value, `space-between`, which is very similar to `space-around` except that it doesn't leave any space at either end. @@ -249,7 +250,7 @@ We'd like to encourage you to play with these values to see how they work before Flexbox also has a feature for changing the layout order of flex items without affecting the source order. This is another thing that is impossible to do with traditional layout methods. -The code for this is simple. Try adding the following CSS to your button bar example code: +Try adding the following CSS to your button bar example code: ```css button:first-child { @@ -259,12 +260,12 @@ button:first-child { Refresh and you'll see that the "Smile" button has moved to the end of the main axis. Let's talk about how this works in a bit more detail: -- By default, all flex items have an {{cssxref("order")}} value of 0. +- By default, all flex items have an {{cssxref("order")}} value of `0`. - Flex items with higher specified order values will appear later in the display order than items with lower order values. -- Flex items with the same order value will appear in their source order. So if you have four items whose order values have been set as 2, 1, 1, and 0 respectively, their display order would be 4th, 2nd, 3rd, then 1st. +- Flex items with the same order value will appear in their source order. So if you have four items whose order values have been set as `2`, `1`, `1`, and `0` respectively, their display order would be 4th, 2nd, 3rd, then 1st. - The 3rd item appears after the 2nd because it has the same order value and is after it in the source order. -You can set negative order values to make items appear earlier than items whose value is 0. For example, you could make the "Blush" button appear at the start of the main axis using the following rule: +You can set negative order values to make items appear earlier than items whose value is `0`. For example, you could make the "Blush" button appear at the start of the main axis using the following rule: ```css button:last-child { @@ -272,13 +273,15 @@ button:last-child { } ``` +While you can change the order using `order`, the tabbing order remains the same as the code order. Changing the order of focusable elements can negatively impact usability for your keyboard users! + ## Nested flex boxes It's possible to create some pretty complex layouts with flexbox. It's perfectly OK to set a flex item to also be a flex container, so that its children are also laid out like flexible boxes. Have a look at [complex-flexbox.html](https://github.com/mdn/learning-area/blob/main/css/css-layout/flexbox/complex-flexbox.html) ([see it live also](https://mdn.github.io/learning-area/css/css-layout/flexbox/complex-flexbox.html)). -![The Sample flexbox example has three flex item children laid out in a row. The first two are the same width, the third is slightly wider. The third flex item is also a flex container. It has a set of buttons in two rows followed by text. The first row of buttons has 4 buttons that are laid out in a row; the buttons are the same width, taking up the full width of the container. The second row has a single button that takes up the entire width of the row on its own. This complex layout where few flex items are treated as flex containers.](flexbox-example7.png) +![The Sample flexbox example has three flex item children laid out in a row. The first two are the same width, the third is slightly wider. The third flex item is also a flex container. It has a set of buttons in two rows followed by text. The first row of buttons has 4 buttons that are laid out in a row; the buttons are the same width, taking up the full width of the container. The second row has a single button that takes up the entire width of the row on its own.](flexbox-example7.png) -The HTML for this is fairly simple. We've got a {{htmlelement("section")}} element containing three {{htmlelement("article")}}s. The third {{htmlelement("article")}} contains three {{htmlelement("div")}}s, and the first {{htmlelement("div")}} contains five {{htmlelement("button")}}s: +This complex layout has a few flex items that are also flex containers. The HTML for this is fairly straightforward. We've got a {{htmlelement("section")}} element containing three {{htmlelement("article")}}s. The third {{htmlelement("article")}} contains three {{htmlelement("div")}}s, and the first {{htmlelement("div")}} contains five {{htmlelement("button")}}s: ```plain section - article @@ -314,7 +317,7 @@ article:nth-of-type(3) { } ``` -Next, we select the first {{htmlelement("div")}}. We first use `flex: 1 100px;` to effectively give it a minimum height of 100px, then we set its children (the {{htmlelement("button")}} elements) to also be laid out like flex items. Here we lay them out in a wrapping row and align them in the center of the available space as we did with the individual button example we saw earlier. +Next, we select the first {{htmlelement("div")}}. We first use `flex: 1 100px;` to effectively give it a minimum height of `100px`, then we set its children (the {{htmlelement("button")}} elements) to also be laid out like flex items. Here we lay them out in a wrapping row and align them in the center of the available space as we did with the individual button example we saw earlier. ```css article:nth-of-type(3) div:first-child { @@ -326,7 +329,7 @@ article:nth-of-type(3) div:first-child { } ``` -Finally, we set some sizing on the button. This time by giving it a flex value of 1 auto. This has a very interesting effect, which you'll see if you try resizing your browser window width. The buttons will take up as much space as they can. As many will fit on a line as is comfortable; beyond that, they'll drop to a new line. +Finally, we set some sizing on the button. This time by giving it a flex value of `1 auto`. This has a very interesting effect, which you'll see if you try resizing your browser window width. The buttons will take up as much space as they can. As many will fit on a line as is comfortable; beyond that, they'll drop to a new line. ```css button { @@ -347,6 +350,11 @@ That concludes our tour of the basics of Flexbox. We hope you had fun and will h ## See also +- [Basic concepts of flexbox](/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox) +- [Aligning items in a flex container](/en-US/docs/Web/CSS/CSS_flexible_box_layout/Aligning_items_in_a_flex_container) +- [Ordering flex items](/en-US/docs/Web/CSS/CSS_flexible_box_layout/Ordering_flex_items) +- [Controlling ratios of flex items along the main axis](/en-US/docs/Web/CSS/CSS_flexible_box_layout/Controlling_ratios_of_flex_items_along_the_main_axis) +- [CSS flexible box layout](/en-US/docs/Web/CSS/CSS_flexible_box_layout) module - [CSS-Tricks Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) — an article explaining everything about Flexbox in a visually appealing way - [Flexbox Froggy](https://flexboxfroggy.com/) — an educational game to learn and better understand the basics of Flexbox