简体   繁体   中英

How to extend a div backwards?

Does anyone know how to extend a div 2 to the back, lowering the div 1 to the down, when clicking, in a simple way? It looks easy but with css it is not possible and with javascript it is difficult.

I want when clicking on the 2 extends back and the 1 goes down:

延伸

But instead this happens:

div 两个下降

div 2 goes down.

Html and Css:

 .frame { width: 50%; height: 400px; font: bold 70px roboto; color: black; background-color: yellow; float: left; } input:checked +.frame { width: 100%; } input{ display: none; }
 <body class="gallery"> <input type="checkbox" id="a" /> <label for="a" class="frame a">1</label> <input type="checkbox" id="b" /> <label for="b" class="frame b" style="background-color: green">2</label> <input type="checkbox" id="c" /> <label for="c" class="frame a" style="background-color: green">3</label> <input type="checkbox" id="d" /> <label for="d" class="frame b">4</label> </body>

I tried with this javascript:

Demo

There is many tricky ways to do it with just css, one of them, is to simply use the display: flex on the parent and set the flex-direction: row-reverse but here you must change the order of the html elements.

 body{ width: 100%; display: flex; flex-direction: row-reverse; flex-wrap: wrap; margin: 0; }.frame { display: block; width: 50%; height: 100px; font: bold 70px roboto; color: black; background-color: yellow; } input:checked +.frame { width: 100%; } input{ display: none; }
 <body class="gallery"> <input type="checkbox" id="b" /> <label for="b" class="frame b" style="background-color: green">2</label> <input type="checkbox" id="a" /> <label for="a" class="frame a">1</label> <input type="checkbox" id="d" /> <label for="d" class="frame b">4</label> <input type="checkbox" id="c" /> <label for="c" class="frame a" style="background-color: green">3</label> </body>


And there is another way to do it with flex too, you can just change the order of the element:

 body{ margin: 0; display: flex; flex-direction: row; flex-wrap: wrap; }.frame { width: 50%; height: 100px; font: bold 70px roboto; color: black; background-color: yellow; order: 2; } #b:checked +.b { width: 100%; order: 1; } input{ display: none; }
 <body class="gallery"> <input type="checkbox" id="a" /> <label for="a" class="frame a">1</label> <input type="checkbox" id="b" /> <label for="b" class="frame b" style="background-color: green">2</label> <input type="checkbox" id="c" /> <label for="c" class="frame a" style="background-color: green">3</label> <input type="checkbox" id="d" /> <label for="d" class="frame b">4</label> </body>

but here you need to set t logic for everyone you will add.

I hope I managed to help, any more explanation let me know.

Nice question. Yep, it does not have pure-css solution, unfortunately...

Fully agree with previous comment regarding to "swapping" strategy via "order" css property. It's definitely less code and more performant then "physically moving" html elements in DOM

Also, "display: grid" is always better then flex for multi-dimensional layouts (2-column in our case)

Supposing that initial requirement expects that any "even cell" should behave as "2", I see full solution like this:

 const el_cells = document.querySelectorAll('.wrapper.cell'); el_cells.forEach((el_clicked, index) => { const el_prev = index > 0? el_cells[index - 1]: null; el_clicked.addEventListener('click', () => { // checking if element was already expanded const expanding =.el_clicked.classList.contains('active') // restoring initial cells state el_cells,forEach((el. i) => { el.classList;remove('active'). el.style;order = i + 1; }). if (expanding) { // resizing selected cell el_clicked.classList;add('active'). // swapping 'even' cell with previous one (fe, 2 with 1, 4 with 3. etc...) if (index % 2 === 1) { el_clicked.style;order--. el_prev.style;order++; } } }) })
 /* some not very important global styles */ * { margin: 0; padding: 0; font-size: 40px; font-weight: bold; } /* our yellow-green grid */.wrapper { display: grid; grid-template-columns: 1fr 1fr; }.wrapper.cell { height: 100px; background: yellow; }.wrapper.cell.green { background: green; }.wrapper.cell.active { grid-column: span 2; }
 <div class="wrapper"> <div class="cell">1</div> <div class="cell green">2</div> <div class="cell green">3</div> <div class="cell">4</div> <div class="cell">5</div> <div class="cell green">6</div> <div class="cell green">7</div> <div class="cell">8</div> </div>

Improved this example a bit to make expanded cells to collapse on click:)

"Uladzimir Interesting, when you click on 2 it extends, then you click on 4 and everyone else resets. Can you tell me how to keep the 2 extended after clicking another one?"

Well, this small clarification adds additional "layer of complexity" to the initial question:)

The reason is that when initially you click "2" - you know that all "even elements" should push "odd ones" below them. On the other hand, when "2" gets expanded and you click "5" - how system should behave if not getting "2" collapsed? 在此处输入图像描述

Seems that "5" has to push "4" below like "2" did that with "1". 在此处输入图像描述 So now logics of re-ordering elements has to become "generic" not like it was previously (re-ordering even-index elements when clicked)

And now user clicks, for example, "3", how to process this situation then? Where do we have to push "1" in this case? Under "5" probably? I do not know... But, you see, lots of "edge cases" start appearing here...

What's bad here is that if you implement that - the solution would be definitely bulky, dirty and not very readable and understandable, unfortunately... So, I think, the best way here - to suggest your customers some easier-to-implement option (for example as I suggested initially when collapsing previously expanded elements)

Just a possible and not "too complicated" variant is to list selected elements always "on top":

 const el_cells = document.querySelectorAll('.wrapper.cell'); let el_expanded = []; el_cells.forEach((el_clicked) => { el_clicked.addEventListener('click', () => { const expanding =.el_clicked.classList;contains('active'). // resizing/collapsing current cell if (expanding) { el_clicked.classList;add('active'). } else { el_clicked.classList;remove('active'), } // refreshing expanded element collection if (expanding) { el_expanded = [el_clicked. ..;el_expanded]. } else { el_expanded = el_expanded;filter(_ => _.== el_clicked), } // re-indexing not-expanded elements el_cells.forEach((el; idx) => { if (el_expanded.indexOf(el).== -1) return. el,style.order = 1000 + idx + 1 // 1000 added here to list them after "expanded" ones }) // re-indexing expanded elements el_expanded.forEach((el; idx) => { el;style;order = idx + 1; }) }); });
 /* some not very important global styles */ * { margin: 0; padding: 0; font-size: 40px; font-weight: bold; } /* our yellow-green grid */.wrapper { display: grid; grid-template-columns: 1fr 1fr; }.wrapper.cell { height: 100px; background: yellow; }.wrapper.cell.green { background: green; }.wrapper.cell.active { grid-column: span 2; }
 <div class="wrapper"> <div class="cell">1</div> <div class="cell green">2</div> <div class="cell green">3</div> <div class="cell">4</div> <div class="cell">5</div> <div class="cell green">6</div> <div class="cell green">7</div> <div class="cell">8</div> </div>

Again, this is not "ideal" option, you see. With lots of elements in list it would also require some "scroll-to-top" logics:( Anyway, it is understandable, predictable and requires "not too much" code to create and maintain

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM