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

时间:2017-12-04 20:58:19

标签: javascript css css3 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,我不确定我甚至可以尝试什么。 (现在我正在考虑一个解决方案,当我们将项目从一个网格手动移动到另一个第二个网格时,它们会溢出,但我不知道检查网格项是否溢出到隐式网格中的方法。)< / p>

Codepen 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>

1 个答案:

答案 0 :(得分:0)

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

.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>