0

Please take a look at the below example. I'm learning css grids. The whole purpose is to keep things simple and to not need to specify distinct layout details on the child elements unnecessarily, so solutions should conform to this pattern.

Given the following:

function toggle(t) {
  document.querySelectorAll('div').forEach(el =>
    el.classList[0] === t.classList[0] ?
    el.classList.toggle('selected') :
    el.classList.remove('selected'))
}
:root,
html,
body,
main {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  height: 100%;
}

main {
  border: solid 3pt white;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
}

div {
  grid-area: span 2 / span 2;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  font-size: 5em;
  font-weight: bold;
  color: white;
  background: grey;
}

.one {
  background: red
}

.two {
  background: green
}

.three {
  background: blue
}

.selected {
  width: 150%;
  height: 150%;
  z-index: 2;
}
<main>
  <div class=one onclick="toggle(event.target)">one</div>
  <div class=two onclick="toggle(event.target)">two</div>
  <div class=three onclick="toggle(event.target)">three</div>
  <div class=four onclick="toggle(event.target)">four</div>
</main>

https://jsfiddle.net/robbie_at_harvard/a3ouq711/1/

Please adjust to cause the areas two, three and four to expand towards the middle instead of always from the top-left corner? Again, preferably with generic rules rather than ones specific to the div.class specifications.

Second question, if I wanted instead a 4x4 layout of 2x2 child elements, where clicking on one element expanded it to 3x3 and contracted the others to 1x2, 2x1, and 1x1 in the opposite corner, what is necessary to produce this solution?

2
  • Use CSS scale instead of width and height? stackoverflow.com/questions/28726430/… Commented Oct 18, 2017 at 13:27
  • that does almost work.. and you could also offset it to offer a complete solution, but then the offset would have to depend on both the selected and the positional class. if I have to use a positional class that's fine, but I was hoping this simpler example at least would not need that. Commented Oct 18, 2017 at 13:30

2 Answers 2

2

You could use transform:scale(1.5) and position it with transform-origin.

It would require specific CSS rules depending on the grid (i use :nth-child to target each element)

For 2x2 use

main div:nth-child(1){transform-origin: top left;}
main div:nth-child(2){transform-origin: top right;}
main div:nth-child(3){transform-origin: bottom left;}
main div:nth-child(4){transform-origin: bottom right;}

.selected {
  transform:scale(1.5);
  z-index: 2;
}

function toggle(t) {
  document.querySelectorAll('div').forEach(el =>
    el.classList[0] === t.classList[0] ?
    el.classList.toggle('selected') :
    el.classList.remove('selected'))
}
:root,
html,
body,
main {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  height: 100%;
}

main {
  border: solid 3pt white;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
}

div {
  grid-area: span 2 / span 2;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  font-size: 5em;
  font-weight: bold;
  color: white;
  background: grey;
}

.one {
  background: red
}

.two {
  background: green
}

.three {
  background: blue
}

main div:nth-child(1) {
  transform-origin: top left;
}

main div:nth-child(2) {
  transform-origin: top right;
}

main div:nth-child(3) {
  transform-origin: bottom left;
}

main div:nth-child(4) {
  transform-origin: bottom right;
}

.selected {
  transform: scale(1.5);
  z-index: 2;
}
<main>
  <div class=one onclick="toggle(event.target)">one</div>
  <div class=two onclick="toggle(event.target)">two</div>
  <div class=three onclick="toggle(event.target)">three</div>
  <div class=four onclick="toggle(event.target)">four</div>
</main>

Sign up to request clarification or add additional context in comments.

Comments

2

I think it's difficult to have a general solution since the 4 blocks need to move in different ways. By the way here a solution that involve few CSS changes.

I know you want a generic one but i think in all the cases you will have some specificities (like the color and the content)

function toggle(t) {
  document.querySelectorAll('div').forEach(el =>
    el.classList[0] === t.classList[0] ?
    el.classList.toggle('selected') :
    el.classList.remove('selected'))
}
:root,
html,
body,
main {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  height: 100%;
}

main {
  position:relative;
  border: solid 3pt white;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
}

div {
  grid-area: span 2 / span 2;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  font-size: 5em;
  font-weight: bold;
  color: white;
  background: grey;
  transition:0.5s;
}

.one {
  background: red;
}

.two {
  background: green;
  right:25%;
}

.three {
  background: blue;
  bottom:25%;
}
.four {
  bottom:25%;
  right:25%;
}
.selected {
  position:relative;
  width:150%;
  height:150%;
}
<main>
  <div class=one onclick="toggle(event.target)">one</div>
  <div class=two onclick="toggle(event.target)">two</div>
  <div class=three onclick="toggle(event.target)">three</div>
  <div class=four onclick="toggle(event.target)">four</div>
</main>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.