WoodrowShigeru
WoodrowShigeru

Reputation: 1606

Flex mixture of column and row, but responsive

I would like to sandwich a vertical layout between two elements for large screens (example-2) – and for small screens, have the left-most and inner-top-most elements next to each other, and then everything else below it (example-3).

But I am trying to prevent having to write two different HTML structures, which is the only way I can currently achieve this. I wonder if I can do this with flexbox.

(function(){
  const toggle_butt = document.querySelector('[name="mobile"]');
  const root_el = document.querySelector('.root');

  if (!toggle_butt || !root_el) {
    return false;
  }

  toggle_butt.onchange = () => {
    if (root_el.classList.contains('mobile')) {
      root_el.classList.remove('mobile');
    } else {
      root_el.classList.add('mobile');
    }
  };
})()
.root {
  max-width: 600px;
  border: 1px dashed gray;
  padding: 0.25rem;
}

.root.mobile {
  max-width: 320px;
}

.controller {
  margin-bottom: 0.5rem;
}

[class*="example-"] + [class*="example-"] {
  margin-top: 1rem;
}

.d-flex {
  display: flex;
  flex-wrap: wrap;
}

.red, .yellow, .green, .blue {
  min-width: 50px;
  min-height: 40px;
}

.red {
  background-color: tomato;
}

.yellow {
  background-color: gold;
  height: 40px;
}

.green {
  background-color: limegreen;
  height: 50px;
}

.blue {
  background-color: cornflowerblue;
}

/* ----------- */

.example-1 .red {
  flex: 0 0 20%;
}

.example-1 .yellow {
  flex: 1 0 70%;
}

.example-1 .green {
  flex: 0 0 100%;
}

.example-1 .blue {
  flex: 0 0 100px;
}

.root.mobile .example-1 .blue {
  flex: 1 0 100%;
}

/* ----------- */

.example-2 .red {
  flex: 0 0 20%;
}

.example-2 .yellow,
.example-2 .green {}

.example-2 .blue {
  flex: 0 0 100px;
}

.example-2 .cheat {
  flex: 1 0 50%;
}

/* ----------- */

.example-3 .red {
  flex: 0 0 20%;
}

.example-3 .yellow {
  flex: 1 0 70%;
}

.example-3 .green,
.example-3 .blue {
  flex: 1 0 100%;
}

.example-3 .cheat {
  display: flex;
  flex: 1 0 100%;
}
<div class="root">
  <div class="controller">
    <label>
      <input type="checkbox" name="mobile" />
      <span class="text">mobile</span>
    </label>
  </div>
  <div class="example-1  d-flex">
    <div class="red"></div>
    <div class="yellow">Can flex do it?</div>
    <div class="green"></div>
    <div class="blue"></div>
  </div>
  <div class="example-2  d-flex">
    <div class="red"></div>
    <div class="cheat">
      <div class="yellow">Goal: desktop</div>
      <div class="green"></div>
    </div>
    <div class="blue"></div>
  </div>
  <div class="example-3  d-flex">
    <div class="cheat">
      <div class="red"></div>
      <div class="yellow">Goal: mobile</div>
    </div>
    <div class="green"></div>
    <div class="blue"></div>
  </div>
</div>

It's not important for green to line up with the bottom edge of red and blue.

Red is an image and yellow is a headline; that is why I'm trying to do this.


StackOverflow questions I looked at (but they're not quite the same):

Upvotes: 0

Views: 267

Answers (1)

sol
sol

Reputation: 22959

You can use Grid's grid-template-areas property:

(function() {
  const toggle_butt = document.querySelector('[name="mobile"]');
  const root_el = document.querySelector('section');

  if (!toggle_butt || !root_el) {
    return false;
  }

  toggle_butt.onchange = () => {
    if (root_el.classList.contains('mobile')) {
      root_el.classList.remove('mobile');
    } else {
      root_el.classList.add('mobile');
    }
  };
})()
div {
  min-height: 40px;
}

.red {
  background: red;
}

.yellow {
  background: yellow;
}

.green {
  background: green;
}

.blue {
  background: blue;
}

section {
  display: grid;
  grid-template-columns: 2fr 5fr 100px;
  grid-template-areas: "r y b" "r g b"
}

.red {
  grid-area: r;
}

.yellow {
  grid-area: y;
}

.blue {
  grid-area: b;
}

.green {
  grid-area: g;
}

section.mobile {
  grid-template-areas: "r y y" "g g g" "b b b"
}
<label>
  <input type="checkbox" name="mobile" />
  <span class="text">mobile</span>
</label>


<section>
  <div class="red"></div>
  <div class="yellow"></div>
  <div class="green"></div>
  <div class="blue"></div>
</section>

Upvotes: 1

Related Questions