Left aligned and centered grid with flexbox

后端 未结 7 2142
半阙折子戏
半阙折子戏 2020-12-30 02:21

I\'d like to implement a responsive grid-like layout using flexbox (without media queries). There can be variable number of elements in the grid. Each item should have fixed

7条回答
  •  北荒
    北荒 (楼主)
    2020-12-30 03:15

    CSS Grid

    CSS Grid solution is the only elegant and flexible CSS solution.

    .container {
      display: grid;
      grid-template-columns: repeat(auto-fill, 200px);
      grid-auto-rows: 200px;
      grid-gap: 10px;
      justify-content: center;
    }
    
    .item {
      background-color: purple;
      padding: 10px;
    }
    Flex item 1
    Flex item 2
    Flex item 3
    Flex item 4
    Flex item 5

    Unfortunately, it doesn't have the best browser support, so if you need outdated browsers like IE you'll have to use Javascript to achieve this. It's due the fact that flexbox container occupies all width even in case when items don't.

    Pure Javascript version

    So basically we are calculating needed value of margin-left to center our flexbox items. This Javascript should work regardless of initial markup settings.

    // get width of element with margins
    function getOuterWidth(el) {
      var styles = window.getComputedStyle(el);
      var margins = parseFloat(styles["marginLeft"]) +
        parseFloat(styles["marginRight"]);
    
      return Math.ceil(el.getBoundingClientRect().width + margins);
    }
    
    // get width of element without paddings
    function getContentWidth(el) {
      var styles = window.getComputedStyle(el);
      var paddings = parseFloat(styles["paddingLeft"]) +
        parseFloat(styles["paddingRight"]);
    
      return Math.ceil(el.getBoundingClientRect().width - paddings);
    }
    
    // Get top of element
    function getTopOfElement(el) {
      return el.getBoundingClientRect().top;
    }
    
    var container = document.querySelector(".container");
    var initialMarginLeft = parseFloat(window.getComputedStyle(container)["marginLeft"]);
    // getting array of items
    var items = Array.prototype.slice.call(document.querySelectorAll(".item"));
    
    function centerItems() {
      if (items.length === 0) return 0;
    
      // set margin-left to initial value to recalculate it
      container.style.marginLeft = initialMarginLeft + "px";
    
      var topOfFirstItem = getTopOfElement(items[0]);
      var spaceTakenByElementsOnFirstLine = getOuterWidth(items[0]);
    
      for (var i = 1; i < items.length; i++) {
        // Break in case we are in second line
        if (getTopOfElement(items[i]) > topOfFirstItem)
          break;
        spaceTakenByElementsOnFirstLine += getOuterWidth(items[i]);
      }
    
      // Set margin-left to center elements
      var marginLeft = initialMarginLeft + (getContentWidth(container) - spaceTakenByElementsOnFirstLine) / 2;
    
      container.style.marginLeft = marginLeft + "px";
    };
    
    window.addEventListener("resize", centerItems);
    
    centerItems();
    .container {
      display: flex;
      flex-wrap: wrap;
    }
    
    .item {
      height: 200px;
      width: 200px;
      background-color: purple;
      padding: 10px;
      margin: 10px;
    }
    Flex item 1
    Flex item 2
    Flex item 3
    Flex item 4
    Flex item 5

    jQuery version

    // get width of element with margins
    function getOuterWidth(el) {
      return $(el).outerWidth(true);
    }
    
    // get width of element without paddings
    function getContentWidth(el) {
      return parseFloat($(el).css("width"));
    }
    
    function getTopOfElement(el) {
      return $(el).position().top;
    }
    
    var $container = $(".container");
    var $items = $(".item");
    var initialMarginLeft = parseFloat($container.css("margin-left"));
    
    function centerItems() {
      if ($items.length === 0) return 0;
    
      // set margin-left to initial value to recalculate it
      $container.css("margin-left", initialMarginLeft + "px");
    
      var topOfFirstItem = getTopOfElement($items[0]);
      var spaceTakenByElementsOnFirstLine = getOuterWidth($items[0]);
    
      for (var i = 1; i < $items.length; i++) {
        // Break in case we are in second line
        if (getTopOfElement($items[i]) > topOfFirstItem)
          break;
        spaceTakenByElementsOnFirstLine += getOuterWidth($items[i]);
      }
    
      // Set margin left to center elements
      var marginLeft = initialMarginLeft + (getContentWidth($container) - spaceTakenByElementsOnFirstLine) / 2;
    
      $container.css("margin-left", marginLeft + "px");
    };
    
    $(window).resize(centerItems);
    
    centerItems();
    .container {
      display: flex;
      flex-wrap: wrap;
    }
    
    .item {
      height: 200px;
      width: 200px;
      background-color: purple;
      padding: 10px;
      margin: 10px;
    }
    
    
    
    Flex item 1
    Flex item 2
    Flex item 3
    Flex item 4
    Flex item 5

提交回复
热议问题