Flexbox.ninja https://flexbox.ninja//feed Some real use cases solved with CSS Flexbox like the holy grail layout, columns with same heights, vertical and horizontal centering, etc. EN Thu, 21 Nov 2024 07:36:40 +0100 Wed, 24 Feb 2021 00:00:00 +0100 http://www.rssboard.org Flexbox.ninja https://flexbox.ninja//feed/assets/images/logo.png https://flexbox.ninja//feed Flexbox.ninja – Solved by Flexbox High Kick 144 80 23 Sunday Holy Grail Layout https://flexbox.ninja//feed/demos/holy-grail-layout/ blog@creativejuiz.fr (Geoffrey Crofte) Wed, 10 Aug 2016 00:00:00 +0200 Flexbox.ninja https://flexbox.ninja//feed/demos/holy-grail-layout/

You certainly already know this layout. The Holy Grail layout is defined as:

The Holy Grail refers to a web page layout which has multiple, equal height columns that are defined with style sheets. It is commonly desired and implemented, although the ways in which it can be implemented with current technologies all have drawbacks. Because of this, finding an optimal implementation has been likened to searching for the elusive Holy Grail.

Wikipedia

Defining the Holy Grail

From the Wikipedia summary, and lot of other researches to find the good way to implement this layout, we are looking for something like that:

  • Sidebars and main content should have the same height, regardless of which element is the tallest,
  • Sidebars should have fixed width and main content fluid width,
  • The center column (main content) should appear first in the HTML source,
  • If the content is sparse, the footer should stay to the bottom of the page,
  • Use a minimal markup and CSS.

Let's code this

First at all, you need to build a basic HTML markup. I propose to you this one, but feel free to adapt or improve regarding your real needs.

HTML

<body class="holy-grail">
	<header>
		<!-- header content -->
	</header>

	<div class="holy-grail-body">

		<section class="holy-grail-content">
			<!-- Main page content -->
		</section>

		<div class="holy-grail-sidebar-1 hg-sidebar">
			<!-- sidebar 1 content -->
		</div>

		<div class="holy-grail-sidebar-2 hg-sidebar">
			<!-- sidebar 2 content -->
		</div>

	</div>

	<footer>
		<!-- footer content -->
	</footer>
</body>

I used explicit classes to make my code easier to read, I suggest you to do so, for you and your team, or for your new you in 6 months!

CSS

To be clear: today, your website has to be responsive. That's why the CSS code I'll propose you is mobile first responsive.

/**
 * Make body at least 100% height
 * You can also use a combination
 * of height: 100% in <html> and
 * min-height: 100% in <body>.
 */
.holy-grail {
	min-height: 100vh;
}

/**
 * Let's do a column distribution
 * (mobile first)
 * flex value is 1 1 auto to make
 * body skrinkable and extensible
 */
.holy-grail,
.holy-grail-body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
}

/**
 * Content body item is made
 * extensible too.
 */
.holy-grail-content {
	flex: 1 1 auto;
}

/**
 * Put the first sidebar before content.
 * If you need sidebar to be before content
 * only in big screen put those 3 next lines
 * in @media block.
 */
.holy-grail-sidebar-1 {
	order: -1;
}

/**
 * Let's introduce bigger screen
 */

@media (min-width: 768px) {
	/**
	 * Body items are now side by side
	 */
	.holy-grail-body {
		flex-direction: row;
	}

	/**
	 * Sidebars have a basic 260 width
	 * and are not really flexible anymore
	 */
	.hg-sidebar {
		flex: 0 0 260px;
	}
}

I hope these comments will help you understand this very short code. You see now how Holy Grail Layout is at your fingertips.

You may now improve this kick-start CSS code introducing more precise break points you need in order to build your perfect website.

]]>
Same Columns Height https://flexbox.ninja//feed/demos/same-height-columns/ blog@creativejuiz.fr (Geoffrey Crofte) Mon, 12 Sep 2016 00:00:00 +0200 Flexbox.ninja https://flexbox.ninja//feed/demos/same-height-columns/

Yeah I know, I can do it with min-height, or perhaps a table-layout… It's what you think, but you are not totally right if you do so. But before talking about right and wrong, let’s define our needs.

Defining the columns behavior

I worked with several designers. You know them, they want to create perfect blocks with right divisions, well measured columns, buttons to the bottom, gorgeous images or icons to illustrate a marketing wording…
Let's define our needs as following:

  • Columns should have same visual height by taking the biggest one,
  • Columns could have same width, but can also be flexible,
  • I want an image at the top, then a title, then a little text and a button/link
  • The link have to be at the bottom-end of the column, no matter the text size above,
  • Use a minimal markup and CSS, only CSS, no JS

Let's code this

First at all, you need to build a basic HTML markup. I propose to you this one, but feel free to adapt or improve regarding your real needs.

HTML

<section>
	<h1>Same Column Height</h1>
	<div class="flex">
		<div class="col">
				
			<a href="#">
				<img src="image.jpg" width="" height="" alt="Some sample words">
			</a>

			<h2>A little title</h2>
			<p>Lorem ipsum dolor sit […]</p>
				
			<a class="btn" href="#">Read more</a>

		</div>

		<div class="col">
				
			<a href="#">
				<img src="image.jpg" width="" height="" alt="Some sample words">
			</a>

			<h2>A little title</h2>
			<p>Lorem ipsum dolor sit amet […]</p>
				
			<a class="btn" href="#">Read more</a>

		</div>

		<div class="col">
				
			<a href="#">
				<img src="image.jpg" width="" height="" alt="Some sample words">
			</a>

			<h2>A little title</h2>
			<p>Lorem ipsum dolor sit amet, consectetur […]</p>
				
			<a class="btn" href="#">Read more</a>

		</div>
	</div>
</section>

Now some styles to make the magic works.

CSS

To be clear: today, your website has to be responsive. That's why the CSS code I'll propose you is mobile first responsive.

/**
 * Make images responsive
 */
.flex .col img {
	width: 100%;
	height: auto;
}

/**
 * Make .flex children same
 * height using display flex.
 * Justify property prepares
 * cols for being centered.
 */
.flex {
	display: flex;
	justify-content: center;
	width: 960px;
	max-width: 100%;
	margin: auto;
}

/**
 * Make cols flexible to
 * auto push button at the
 * col bottom.
 */
.flex .col {
	display: flex;
	flex-direction: column;
	flex: 1 1 300px;
	/* 
	In the order, equal to
	flex-grow: 1;
	flex-shrink: 1;
	flex-basis: 300px;
	*/
	margin: 1em;
}

/**
 * Margin-top auto pushes
 * button to bottom.
 * Align self makes button
 * stuck to the left.
 */
.flex .col .btn {
	align-self: flex-start;
	margin-top: auto;
}

/**
 * Under 900px wrap cols
 */
@media (max-width: 900px) {
	.flex {
		flex-wrap: wrap;
	}
}

In that precise case, I allowed images to be very big, larger than their physical width in intermediate screen sizes. (iPad mini in portrait, or something…)
If you need to keep a real good feeling about images, grab a solution among size and srcset attributes, or simply decide to replace flex: 1 1 300px; by flex: 0 1 300px; that allows cols being smaller but not bigger than 300 pixels wide.

I hope these comments will help you understand this very short code.Yeah, as you can see, it's pretty easy to do it work.

Sure, there are many other ways to make the same thing differently. Feel free to adapt it and make your own code.

]]>
Website Header https://flexbox.ninja//feed/demos/website-header/ blog@creativejuiz.fr (Geoffrey Crofte) Fri, 16 Sep 2016 00:00:00 +0200 Flexbox.ninja https://flexbox.ninja//feed/demos/website-header/

This is awesome! A logo to the left, a navigation to the right.
It's not a big deal, but this tip could save your time during a lot of projects.

Defining our needs

I think there are two ways to handle this kind of situation, but only CSS will change the game. My list of needs:

  • A logo to the left, a navigation to the right,
  • Logo and navigation have to be vertically centered,
  • Horizontal alignement have to be shared between logo and nav
  • When screen width becomes not enough for both in the same row, logo and nav have to be in two different centered-content lines.
  • (Optional) When both are in the same line logo is stuck to the very left, nav to the very right

I put this last item as optionnal, because… it depends on the project you are doing, but the need can happens.

Let's code this

Our HTML basics

<header class="main-header">
	<div class="container">
		<h1 class="mh-logo">
			<img src="http://flexbox.ninja/assets/images/logo.svg" width="170" height="95" alt="Flexbox.ninja">
		</h1>
		<nav class="main-nav">
			<ul class="main-nav-list">
				<li>
					<a href="#">Home</a>
				</li>
				<li>
					<a href="#">About us</a>
				</li>
				<li>
					<a href="#">Our clients</a>
				</li>
				<li>
					<a href="#">Contact</a>
				</li>
			</ul>
		</nav>
	</div>
</header>

I use a lot of classes so you can easily chose your own markup.
In this case, the .container element is here to limit header content width in big screens.

CSS to flex the things

It's time to define the main rules that make this magic appears. Feel free to see the complete demo file to grab some other tips.

/**
 * Images a now responsive
 */
img {
	max-width: 100%;
	height: auto;
}

/**
 * Limit the container in
 * width for big screens
 */
.container {
	width: 960px;
	max-width: 100%;
	padding: 20px;
	margin: 0 auto;
}

/**
 * By using display: flex
 * Logo and nav are in 2 cols
 * align-items make them
 * vertically centered
 * justify-content distribute
 * horizontal spaces around
 * and flex-wrap break the
 * things in two lines in
 * small screens
 */
.main-header .container {
	display: flex;
	align-items: center;
	justify-content: space-around;
	flex-wrap: wrap;
}

/**
 * The followings are to
 * make things more
 * clean and airy
 * and contents centered
 */
.main-nav ul {
	margin: 1em 0 .5em;
	text-align: center;
}
.main-nav li {
	display: inline;
}
.main-nav a {
	display: inline-block;
	padding: .5em 1.5em;
}

Magic part is at .main-header .container selector with all the flex-things. With that, we don't have the last (optionnal) point of our list.

I propose to you an alternative by pointing only the differences in this following CSS code:

/**
 * Space-around become
 * Space-between to
 * distribute space
 * between the flex-items
 */
@media (min-width: 960px) {
	.main-header .container {
		justify-content: space-between;
	}
}

Here, the breakpoint is defined by the maximum width of my .container. I think it's an at-least value, but feel free to adjust it according to your project.

]]>
Buttons with Icons https://flexbox.ninja//feed/demos/buttons-with-icons/ blog@creativejuiz.fr (Geoffrey Crofte) Sat, 11 May 2019 00:00:00 +0200 Flexbox.ninja https://flexbox.ninja//feed/demos/buttons-with-icons/

The most common case for this kind of pattern is when you need to build buttons for social network sharing.

Defining our needs

As usual, I like to define some goals so that the CSS solution does make sense to you. What I need is:

  • Vertical aligned buttons
  • Buttons with vertical aligned icon and text
  • If I don't have enough space, the overflowing buttons go to a new line.
  • Buttons cover the entire space available by distributing the available space.
  • Keep the HTML code as simple and accessible as possible, as usual :p

The last part is optional.

Let's code this

Our HTML basics

<ul class="social-buttons">
	<li>
		<a href="https://twitter.com/">
			<i class="icon-twitter" role="presentation"></i>
			Twitter
		</a>
	</li>
	<li>
		<a href="https://www.facebook.com/">
			<i class="icon-facebook" role="presentation"></i>
			Facebook
		</a>
	</li>
	<li>
		<a href="https://instagram.com">
			<i class="icon-instagram" role="presentation"></i>
			Instagram
		</a>
	</li>
	<li>
		<a href="http://weibo.com/">
			<i class="icon-weibo" role="presentation"></i>
			Weibo
		</a>
	</li>
	<li>
		<a href="https://www.linkedin.com/">
			<i class="icon-linkedin" role="presentation"></i>
			Linkedin
		</a>
	</li>
</ul>

I used role="presentation" to avoid assistive technology reading the decorative icon. Read more about that thanks to the excellent article by Scott O'Hara "Know your ARIA: 'hidden' VS 'none'".

CSS to flex the things

Ok now we are using Flexbox to make the magic happen.

/**
 * The container and the item are both
 * into flex layout. To align items
 * to each other.
 */
.social-buttons,
.social-buttons li {
	display: flex;
	padding: 0;
	margin: 0;
}

/**
 * Force to occupy the space available
 * and allow item being on several lines
 */
.social-buttons {
	width: 100%;
	list-style: none;
	flex-wrap: wrap;
}

/**
 * Items tend to occupy 25% of
 * the available width but are
 * allow to grow.
 */
.social-buttons li {
	flex-basis: 25%;
	flex-shrink: 0;
	flex-grow: 1;
}

/**
 * The anchor is also in Flex
 * to align icon and text and
 * center their content.
 */
.social-buttons a {
	display: flex;
	justify-content: center;
	align-items: center;
	width: 100%;
	padding: .5em 1em;
	font-weight: 500;
	text-decoration: none;
	color: #FFF;
}

/**
 * Some decorations for the 
 * next lines.
 */
.social-buttons i {
	margin-right: .5em;
}

.social-buttons [href*="twitter.com"] {
	background: #1da1f2;
}

.social-buttons [href*="facebook.com"] {
	background: #3b5998;
}

.social-buttons [href*="instagram.com"] {
	background: #c13584;
}

.social-buttons [href*="weibo.com"] {
	background: #e6162d;
}

.social-buttons [href*="linkedin.com"] {
	background: #0077b5;
}

The magic parts are here the wrap option and the fact that .social-buttons li are allow to grow even if their width is set thanks to flex-basis: 25% which is not a strong constraint

Here is an alternative code with margin:

.social-buttons li {
	margin: 2px;
}

Have fun!

]]>
Pricing Table https://flexbox.ninja//feed/demos/pricing-table/ blog@creativejuiz.fr (Geoffrey Crofte) Wed, 24 Feb 2021 00:00:00 +0100 Flexbox.ninja https://flexbox.ninja//feed/demos/pricing-table/

Pricing Table is all over the internet with a lot of different patterns. I tried to cover the archetype of this kind of component here.

Defining our Pricing Table needs

As usual, I'll define some goals so that the CSS solution does make sense to you. What I need for this pricing table is:

  • Same Column Height already seen in Flexbox.ninja
  • All call to action at the same level
  • One highlighted columns
  • Flexible amount of items
  • Keep the HTML code as simple and accessible as possible, as usual 😘

Let's code our Pricing Table

Our HTML basics

Here is my piece of HTML. Just add any item you want PT-Item and the class .is-highlighted to the item you want to highlight.

<section class="Pricing-Table">
	<article class="PT-Item">
		<header class="PT-Heading">
			<h2 class="PT-Title">Free</h2>
			<p class="PT-Subtitle">Forever, promise.</p>
		</header>

		<ul class="PT-Features">
			<li class="PT-Feature">Unlimited Items</li>
			<li class="PT-Feature">2 Team Members</li>
			<li class="PT-Feature">3 Projects</li>
			<li class="PT-Feature">Cloud Storage (2Gb)</li>
		</ul>

		<div class="PT-Footer">
			<p class="PT-Price">
				<small>$</small>
				<span class="PT-nb">0</span>
				<small>/month</small>
			</p>
			<p class="PT-Trial">14-day money back guarantee</p>
			<p class="PT-CTA">
				<a href="#" class="button">Buy this one</a>
			</p>
		</div>
	</article>
	
	<!-- ... repeat -->

</section>

I used a ul element for the list of features, because it's a list so it makes sense using semantic HTML. Same for the rest of the HTML element choices here 😊

You can totally use Microdata (FR) in this case to improve the code of your pricings.

CSS to flex the Pricing Table

Ok now what I need is to have a two dimension flex context. The first one is for making the items next to each other and stretch by default. The second is to put the content of each item in a column direction to put the footer at the very bottom of an offer.

/**
 * The container is in a Flex layout
 * with a gap of 24px
 */
.Pricing-Table {
	--gap: 24px;
	--nb-items: 3;
	/* I used CSS Variables here to 
	 * facilitate the calculation
	 * of width suggestion later.
	 */

	display: flex;
	justify-content: center;
	/* Make it wrap in case we have too many items */
	flex-wrap: wrap;
	gap: var(--gap);

	/* Just design purpose */
	width: 1040px;
	max-width: 100%;
	padding: 32px;
}

/**
 * Below a bit of magic to count
 * the number of items.
 * I stopped over 5 on purpose.
 */
.PT-Item:nth-last-child(4):first-child, 
.PT-Item:nth-last-child(4):first-child ~ .PT-Item {
	--nb-items: 4;
}

.PT-Item:nth-last-child(5):first-child, 
.PT-Item:nth-last-child(5):first-child ~ .PT-Item {
	--nb-items: 5;
}

/**
 * Flex direction column to put our
 * footer at the very bottom.
 */
.PT-Item {
   /* Preparing for themed item */
	--primary: #F34A4E;

	display: flex;
	flex-direction: column;
	flex-grow: 1;
	/* Be careful with max-content value */
	min-width: max-content;
	background: white;
	border-radius: 24px;
	overflow: hidden;
	/**
	 * The calc here is a way to keep thing out
	 * of the wrapping behavior for a while.
	 * Above 5 items it stops and go back
	 * to --nb-items = 3
	 */
	flex-basis: calc( calc(100% - (var(--gap) * var(--nb-items)) )/var(--nb-items) );
}

.PT-Item.is-highlighted {
	/* Preparing for highlighted item */
	--primary: #1FA19C;
	transform: scale(1.05);
}

/**
 * Most of the rest is for
 * decorative purpose.
 */

.PT-Item > * {
	padding: 24px;
}

.PT-Item p,
.PT-Item ul,
.PT-Item h2 {
	margin-top: 0;
	margin-bottom: 0;
}

.PT-Heading {
	text-align: center;
	color: white;
	background: var(--primary);
}

.PT-Feature {
	font-size: .875em;
	padding: 8px 0;
	list-style: none;
}

.PT-Feature + .PT-Feature {
	border-top: 1px solid #eee;
}

.PT-Footer {
	padding-top: 0;
	margin-top: auto;
	text-align: center;
}

.PT-Price {
	font-size: 2.5rem;
	color: var(--primary);
}

.PT-Price small {
	margin: 0 -.25em;
	font-size: 1rem;
	color: #777;
}

.PT-Trial {
	font-size: .75em;
	color: #777;
}

The magic parts here are the wrap option and the fact that .PT-Item width is determined by the flex-basis calculation. Above 5 items I stopped counting on purpose, but feel free to adjust this code for your needs.

There is no need for responsive complement here since the entire component is wrapping naturally.

Have fun!

]]>