javascript - 使用 CSS Grids,有没有办法在使用 grid-auto-flow : column? 时包装隐式网格

标签 javascript css grid-layout css-grid

我正在尝试使用 4x2 网格实现布局,该网格(使用 grid-auto-flow: column )流入下面的第二个 4x2 网格。从本质上讲,我试图将一个 8x2 的网格切成两半,并将两半放在另一半上。有没有办法让这个布局环绕自己?

What I'm trying to achieve.

到目前为止,我的网格布局为

grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, 1fr);

并且子节点分为3类:小、中、大

.c-small { }

.c-medium {
  grid-row: auto / span 2;
}

.c-large {
  grid-column: auto / span 2;
  grid-row: auto / span 2;
}

有没有办法让我将隐式网格包裹到底部而不是将它砸在网格的右侧?

如果没有 JS,我不确定我什至可能尝试什么。 (现在我正在考虑一种解决方案,当它们溢出时,我手动将元素从一个网格移动到单独的第二个网格,但我不知道有什么方法可以检查网格元素是否已溢出到隐式网格中。)

密码笔 here

// VARS
var count = 0;

// HELPERS
function grab(id) {
  return document.getElementById(id);
}

// GRIDS
var grid1 = {
  spaceLeft: 8,
  add: function(size) {
    switch (size) {
      case 'S':
        this.addToBack(createEmptySmall())
        break;
      case 'M':
        this.addToBack(createEmptyMedium())
        break;
      case 'L':
        this.addToBack(createEmptyLarge())
        break;
      default:
    }
  },
  prep: function(elem) {
    // if (elem === undefined) { break; }

    switch (elem.getAttribute('size')) {
      case "S":
        this.spaceLeft -= 1;
        break;
      case "M":
        this.spaceLeft -= 2;
        break;
      case "L":
        this.spaceLeft -= 4;
        break;
      default:
    }
    
    return elem;
  },

  addToFront: function(elem) {
    elem = this.prep(elem);
    addToFront(grab('js-grid1'), elem);
  },

  addToBack: function(elem) {
    elem = this.prep(elem);
    addToBack(grab('js-grid1'), elem);
  },
}

var grid2 = {
  spaceLeft: 8,
  addToFront: function(elem) {
    if (elem === undefined) {
      elem = createEmptyMedium()
    }
    // switch (elem.getAttribute('size')) {
    //   case "S":
    //     this.spaceLeft -= 1;
    //     break;
    //   case "M":
    //     this.spaceLeft -= 2;
    //     break;
    //   case "L":
    //     this.spaceLeft -= 4;
    //     break;
    //   default:
    //
    // }
    addToFront(grab('js-grid2'), elem);
  }
}

//METHODS
function createEmptySmall() {
  var elem = document.createElement("div");
  elem.classList.add("a-grid__item", "c-small");
  elem.setAttribute('size', "S");
  count++;
  elem.innerHTML = count.toString();

  return elem;
}

function createEmptyMedium() {
  var elem = document.createElement("div");
  elem.classList.add("a-grid__item", "c-medium");
  elem.setAttribute('size', "M");
  count++;
  elem.innerHTML = count.toString();

  return elem;
}

function createEmptyLarge() {
  var elem = document.createElement("div");
  elem.classList.add("a-grid__item", "c-large");
  elem.setAttribute('size', "L");
  count++;
  elem.innerHTML = count.toString();

  return elem;
}

function addToFront(grid, elem) {
  grid.insertBefore(elem, grid.childNodes[0]);
}

function addToBack(grid, elem) {
  grid.appendChild(elem, grid.childNodes[0]);
}

function shift() {
  var elem = grab('js-grid1').lastElementChild;
  grid2.addToFront(elem);
}

function changeSize(elem, size) {
  console.log('hit');
  if (size === undefined) {
    switch (elem.getAttribute('size')) {
      case "S":
        size = "M"
        break;
      case "M":
        size = "L"
        break;
      case "L":
        size = "S"
        break;
      default:
        size = "M";
    }
  }

  if (size == "S" || size == "M" || size == "L") {
    elem.setAttribute('size', size);

    switch (elem.getAttribute('size')) {
      case "S":
        elem.className = "a-grid__item c-small"
        break;
      case "M":
        elem.className = "a-grid__item c-medium"
        break;
      case "L":
        elem.className = "a-grid__item c-large"
        break;
      default:

    }
  }
}
/* OVERRIDES */
body {
  font-family: sans-serif;
  margin: 0;
  min-height: inherit !important;
}

/* LAYOUTS */
.l-canvas {
  width: 100%;
  height: calc(100vh - 70px);
  background-color: rgba(0, 0, 0, 0.05);
}

.l-grid {
  height: calc(50vh - 70px - 32px);
  /* 100vh */
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(2, 1fr);
  grid-column-gap: 16px;
  grid-row-gap: 16px;
  grid-auto-flow: column;
  padding: 16px;
}

.l-buttons {
  position: fixed;
  bottom: 0;
  right: 0;
  height: 56px;
  padding: 16px 16px;
}

/* ATOMS */
.a-grid__item {
  background-color: rgba(0, 0, 0, 0.2);
  /* height: 200px; */
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
}

/* COMPONENTS */
.c-title {
  font-size: 24px;
  font-weight: bold;
  line-height: 28px;
  padding-bottom: 8px;
  margin: 16px 8px;
  border-bottom: 2px solid #333;
}

.c-small {
  /* auto */
}

.c-medium {
  grid-row: auto / span 2;
}

.c-large {
  grid-column: auto / span 2;
  grid-row: auto / span 2;
}
<div class="c-title">
  CSS Grids
</div>
<div class="l-canvas">
  <div id="js-grid1" class="l-grid">
    <div class="a-grid__item c-small" onclick="changeSize(this)">
      1
    </div>
    <div class="a-grid__item c-small" onclick="changeSize(this)">
      2
    </div>
    <div class="a-grid__item c-medium" onclick="changeSize(this)">
      3
    </div>
    <div class="a-grid__item c-small" onclick="changeSize(this)">
      4
    </div>
    <div class="a-grid__item c-medium" onclick="changeSize(this)">
      5
    </div>
  </div>
  <div id="js-grid2" class="l-grid">
    <div class="a-grid__item c-small" onclick="changeSize(this)">
      6
    </div>
    <div class="a-grid__item c-large" onclick="changeSize(this)">
      7
    </div>
    <div class="a-grid__item c-medium" onclick="changeSize(this)">
      8
    </div>
  </div>
</div>

最佳答案

首先,您需要隐藏网格中的所有溢出元素。为此,我更改了网格的样式。

.l-grid {
  height: calc(50vh - 70px - 32px);
  display: grid;
  /* fixed percentage minus (n-1)/n * column gap, n is column count */
  /* with calc to include gaps instead of flexible fr units */
  grid-template-columns: repeat(4, calc(25% - 12px));
  grid-template-rows: repeat(2, 1fr);
  /* set auto generated column width to 0 */ 
  grid-auto-columns: 0;
  /* hide when overflow */
  overflow: hidden;
  grid-gap: 16px;
  grid-auto-flow: column;
  margin: 16px;
}

在 JavaScript 中,我添加了函数 changeSize根据 CSS 类更改大小。

然后我添加了功能 isHidden计算网格项是否隐藏基于右侧的坐标(因为溢出时可以裁剪两列项)。

最后 moveHiddenElementsToNextGrid功能恢复原始布局并将不可见的元素移动到第二个网格。

$(".a-grid__item").click(function() {
  var $gridItem = $(this);
  changeSize($gridItem);
  moveHiddenElementsToNextGrid();
});

function changeSize($gridItem) {
  if ($gridItem.hasClass("c-small")) {
    $gridItem.removeClass("c-small");
    $gridItem.addClass("c-medium");
  } else if ($gridItem.hasClass("c-medium")) {
    $gridItem.removeClass("c-medium");
    $gridItem.addClass("c-large");
  } else if ($gridItem.hasClass("c-large")) {
    $gridItem.removeClass("c-large");
    $gridItem.addClass("c-small");
  }
}

function isHidden($gridItem) {
    var elementRight = $gridItem.position().left + $gridItem.width();
    var parentWidth = $gridItem.parent().width();
    var parentMarginRight = parseInt($gridItem.parent().css("margin-right"));
    return elementRight - parentWidth > parentMarginRight;
};

function moveHiddenElementsToNextGrid() {
  $(".a-grid__item").appendTo("#js-grid1");
  $(".a-grid__item").filter(function() { return isHidden($(this)); }).appendTo("#js-grid2");
}

moveHiddenElementsToNextGrid();
/* OVERRIDES */

body {
  font-family: sans-serif;
  margin: 0;
}


/* LAYOUTS */

.l-canvas {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: calc(100vh - 70px);
  background-color: rgba(0, 0, 0, 0.05);
}

.l-grid {
  height: calc(50vh - 70px - 32px);
  /* 100vh */
  display: grid;
  grid-template-columns: repeat(4, calc(25% - 12px));
  grid-template-rows: repeat(2, 1fr);
  grid-auto-columns: 0;
  overflow: hidden;
  grid-gap: 16px;
  grid-auto-flow: column;
  margin: 16px;
}

.l-buttons {
  position: fixed;
  bottom: 0;
  right: 0;
  height: 56px;
  padding: 16px 16px;
}


/* ATOMS */

.a-grid__item {
  background-color: rgba(0, 0, 0, 0.2);
  /* height: 200px; */
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  min-width: 0;
}


/* COMPONENTS */

.c-title {
  font-size: 24px;
  font-weight: bold;
  line-height: 28px;
  padding-bottom: 8px;
  margin: 16px 8px;
  border-bottom: 2px solid #333;
}

.c-small {
  /* auto */
}

.c-medium {
  grid-row: auto / span 2;
}

.c-large {
  grid-column: auto / span 2;
  grid-row: auto / span 2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="c-title">
  CSS Grids
</div>
<div class="l-canvas">
  <div id="js-grid1" class="l-grid">
    <div class="a-grid__item c-small">
      1
    </div>
    <div class="a-grid__item c-small">
      2
    </div>
    <div class="a-grid__item c-medium">
      3
    </div>
    <div class="a-grid__item c-small">
      4
    </div>
    <div class="a-grid__item c-medium">
      5
    </div>
    <div class="a-grid__item c-small">
      6
    </div>
    <div class="a-grid__item c-large">
      7
    </div>
    <div class="a-grid__item c-medium">
      8
    </div>
  </div>
  <div id="js-grid2" class="l-grid">
  </div>
</div>

关于javascript - 使用 CSS Grids,有没有办法在使用 grid-auto-flow : column? 时包装隐式网格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47641846/

相关文章:

javascript - 使用 jQuery 显示/隐藏循环中生成的具有特定类和 id 的表行

html - 使用标签、href 和 css 的链接在 IE 中不起作用

css - 页面上有 2 个 Bootstrap 导航栏 - 一切正常,但第二个汉堡包未显示

CSS 网格 : content to use free space but scroll when bigger

java - 为什么我的子 JPanel 会在父 JPanel 中移动或错位?

java - 在 GridLayout 布局管理器中动态调整链接到 JLabels 的图像大小

javascript - SmoothSate.js 问题

javascript - 当元素在 AngularJS 中可见时运行一些 DOM 操作

javascript - 导入json文件时webpack报错

html - CSS:在标题上包装背景颜色