Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align items with different heights in a grid and have them match lines of alignment

I want to create a page where my elements are displayed in a Grid. I want to align the items by line. I want to achieve visually the following result, but I don't know how: https://codepen.io/shirkit/pen/KvZKOE/

And I currently have this:

var back = ["red","blue","gray","black","green","cyan","brown","magenta"];
var i = 0;

$('#container .card').children().each(function() {
 $(this).css('background-color',back[i++]);
 if (i == back.length) i = 0;
});
#container {
 display: flex;
 flex-direction: row;
}

.card {
 max-width: 200px;
  width: 100%;
}

.card .image {
 height: 150px;
}

.card .text {
 height: 100px;
}

.card .list {
 height: 50px;
}

#z1 .image {
  height: 175px;
}

#z2 .text {
  height: 120px;
}

#z3 .list {
  height: 60px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
 <div id="z1" class="card">
  <div class="image"></div>
  <div class="text"></div>
  <div class="list"></div>
 </div>
 <div id="z2" class="card">
  <div class="image"></div>
  <div class="text"></div>
  <div class="list"></div>
 </div>
 <div id="z3" class="card">
  <div class="image"></div>
  <div class="text"></div>
  <div class="list"></div>
 </div>
</div>

Clarification: the heights on the ID selectors #z1 .image, #z2.text #z3 .list are there just for simulating the height that the components would have. Therefore, it's NOT an option to change those values. Also note that height values of those elements/containers are not known in advance, so setting margin is also NOT an option.

The current code shown is not how it's currently, it's just for show how visually currently looks, but it should follow that structure, a container for everything, a card for the element and the items inside the card.

Now I know how to do this if I don't put the items in the .card element, and then using the CSS display: grid in #container. I would have the elements .image/.text/.list as direct children from #container, but this is the last resort, I wanted an alternative.

I'm currently looking for a solution that allows for me to keep the .card elements, and have possible fallbacks.

Edit: The proposed answers that were marked as duplicates does not solves the issue I presented here, or I haven't found any others related.

like image 375
SHiRKiT Avatar asked Aug 16 '17 18:08

SHiRKiT


People also ask

How do you align objects in grid?

To align the item horizontally within the grid, we use the justify-content property and set it to center . With justify-content we can align the columns start , end , stretch or center .

How do I align grid items to the right?

Instead set column width:100px inside the grid, because grid is the container also use justify-content:end; to align the content to the right side.

Which CSS rule will you use to place a grid item into the grid so that it starts from the second column and second row and spans three columns and two rows?

Auto-placement by column Using the property grid-auto-flow with a value of column . In this case grid will add items in rows that you have defined using grid-template-rows . When it fills up a column it will move onto the next explicit column, or create a new column track in the implicit grid.

How do I align text in grid?

text-align: center To center content horizontally in a grid item, you can use the text-align property. Note that for vertical centering, vertical-align: middle will not work. This is because the vertical-align property applies only to inline and table-cell containers.


1 Answers

With your current HTML structure, I'm not familiar with any pure CSS ways of achieving your end result. The key issue is that the individual elements in each adjacent column have no way of relating themselves to their surroundings. If your cells were horizontal, we might be able to use CSS like table-row - because "cells are descendants of rows, never of columns." (W3)

With that said, you didn't mention you were looking for a pure CSS solution, and as you already are using jQuery, I thought that would be a fine solution for keeping your HTML structure while achieving your desired layout.

In the code below I'm iterating through each set of components (image, text, list) to determine which card has the tallest one for each, then spacing out the other cards using margin-bottom on each of those shorter components to make them equal.

var back = ["red", "blue", "gray", "black", "green", "cyan", "brown", "magenta"];
var i = 0;

$('#container .card').children().each(function() {
  $(this).css('background-color', back[i++]);
  if (i == back.length) i = 0;
});

var components = ['image', 'text', 'list'];
$.each(components, function(i, j) {
  var $elements = $('.card .' + j);
  var heights = [];
  var tallest = 0;

  $elements.each(function(i) {
    var height = $(this).height();
    heights[i] = height;
    if (height > tallest) {
      tallest = height;
    }
  });

  $.each(heights, function(i, j) {
    var diff = tallest - j;
    if (diff) {
      $elements.eq(i).css('margin-bottom', diff);
    }
  });
});
#container {
  display: flex;
}

.card {
  max-width: 200px;
  width: 100%;
}

.card .image {
  height: 150px;
}

.card .text {
  height: 100px;
}

.card .list {
  height: 50px;
}

#z1 .image {
  height: 175px;
}

#z2 .text {
  height: 120px;
}

#z3 .list {
  height: 60px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div id="z1" class="card">
    <div class="image"></div>
    <div class="text"></div>
    <div class="list"></div>
  </div>
  <div id="z2" class="card">
    <div class="image"></div>
    <div class="text"></div>
    <div class="list"></div>
  </div>
  <div id="z3" class="card">
    <div class="image"></div>
    <div class="text"></div>
    <div class="list"></div>
  </div>
</div>
like image 188
Jon Uleis Avatar answered Sep 28 '22 09:09

Jon Uleis