Recently, we were working on a very interesting problem. The problem statement is as below.
1. We need to show 3 sections with a finite number of blocks in it. In the initial state, this will look something as below.
2. When a user hovers over any of the blocks, the block gets expanded and the layout will be changed to something as below.
At first, this seems to be a bit complex problem, as we need to find out when these sections can v/s cannot fit in one line and then based on that change some CSS on the fly. And as all of us know that this would require to add a lot of javascript for width calculations on hover, which is very expensive and might hurt the performance. And as a UI developer, anyone knows that this is not happening as we don’t want to do computations on browser events.
After syncing upon this problem with some expert CSS personnel, we found that this can be done by using CSS Flex. At first, we will show the working code and then we will explain how this works.
Code
<style> .parent { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; border: 1px solid; resize: horizontal; overflow: auto; background-color: #000; } .parent-wrap { display: flex; flex-grow: 1; } .parent-wrap-1 { flex-grow: 999; } .wrap1, .wrap2, .wrap3 { display: flex; justify-content: flex-start; } .wrap2 { flex-grow: 100; } .block { padding: 20px 30px; transition: all 0.5s; background-color: #d3dada; } .block:not(first-of-type) { margin: 10px; } .block:hover { padding: 20px 60px; } </style> <div class="parent"> <div class="parent-wrap parent-wrap-1"> <div class="wrap1"> <div class="block">A</div> <div class="block">B</div> <div class="block">C</div> <div class="block">D</div> </div> </div> <div class="parent-wrap parent-wrap-2"> <div class="wrap2"> <div class="block">E</div> <div class="block">F</div> </div> <div class="wrap3"> <div class="block">G</div> <div class="block">H</div> </div> </div> </div>
Working Example
Code Breakdown
display: flex;
As we can see, line 3, 14 & 25 sets all the parent containers to display flex. This is required to set the flex-grow property on the containers.
justify-content: space-between;
This line makes sure that all the sections are evenly distributed in the line.
flex-wrap: wrap;
By default, flex items will all try to fit onto one line. You can change that and allow the items to wrap as needed with this property.
flex-grow: 999;
Line 19 adds the flex-grow property for section1. What flex-grow property tries to do is it tries to grow the container in the specified proportion.
For e.g., if you assign flex-grow to container A as 1 and container B as 2, then container B will grow 2 times in comparison to container A when the space surrounding allows.
In our case, specifying line 19 will always push Section2 & 3 to the right of section 1, until all 3 sections fit in a single line.
flex-grow: 100;
Line 30 sets the flex-grow property of section-2 to 100. We need to assign less value of the flex-grow property to section-2 in comparison to section-1 for two reasons.
1. When all three sections can fit in one line, line 19 & 30 will force section 2 & 3 to the right of section 1 and also makes sure that section 2 & 3 look as a single section.
2. When three sections are not able to fit in a single line, line 30 will make section 2 to grow 100 times more in comparison to section 3. This will force section 2 to the left of the line and section 3 to the right.
justify-content: flex-start;
This will force all the sections to be packed toward the start of the flex-direction.
This is all we need to do to solve the problem. As you can see, we don’t need any javascript here and we don’t listen to any browser or element events, at all, which increases the overall performance.
We hope you found this article useful. We will be back with some more interesting articles. Until then, HAPPY CODING!!!