7

I have a series of articles

<section>
<article>1</article>
<article>2</article>
<article>3</article>
....
<article>999</article>
<section>

arranged in a grid of three per row

section { 
  position: relative 
}
article { 
  display: inline-block; 
  width: 33%;
} 

and I want that they expand horizontally to fully occupy its row when clicked.

so I create an expanded class

.expanded {
  position:absolute;
  left:0px;
  width: 100%;
}

and apply it on click

$("article").click(function(){ 
  $(this).toggleClass("expanded"); 
});

I am almost there, as you can see in the fiddle here http://jsfiddle.net/aqw339r0/1/

When I click on any of the articles they expand to the full width of the row; but the problem is that when I click the first article of a row (except the first row) it "jumps" to the row immediately above.

I have tried changing the position and display attributes of both article and .expanded but I cannot get the behavior I need. For example: When I change the position:absolute of .expanded, the blocks 5 and 6, "jump" to the row below. Similar when I remove display:inline-block and change to float:left.

Do you have any ideas of why this happens and how to correct it?

PA.
  • 28,486
  • 9
  • 71
  • 95
  • 1
    what if you remove `position:absolute`? that seems to resolve it – stackoverfloweth Oct 06 '15 at 14:32
  • https://jsfiddle.net/aqw339r0/2/ – stackoverfloweth Oct 06 '15 at 14:32
  • @godmode That pushes the other div off-screen; probably not the behavior or visual effect PA. wants. – TylerH Oct 06 '15 at 14:33
  • @goodmode, yes it apparently solves the problem, but in fact, it creates another; as it flips the behavior, so for the 1st in the row it stays in the same row, but makes the others "jump" to the row below. I'd want to have all the blocks expanded in the same row they already are on. – PA. Oct 06 '15 at 14:38
  • 1
    I assume that it's impossible to make rows, really? This is, wrap each 3 elements in a position relative box. Can you? – Marcos Pérez Gude Oct 06 '15 at 14:49
  • 1
    why this happens is pretty clear...you are changing the document flow – charlietfl Oct 06 '15 at 15:02
  • Oh! Surprise! One answer with the articles wrapped xD . It's very complicated if you don't change the html, but I promise you I will going to search a solution without wrapping – Marcos Pérez Gude Oct 06 '15 at 15:09
  • I think that you can make it with flexbox, but I'm not sure how to achieve the columns, I'm newbie with flexbox. If you put the `section` with `display:flex` you can play with it. A visual guide with a toy to play: https://scotch.io/tutorials/a-visual-guide-to-css3-flexbox-properties . Good luck – Marcos Pérez Gude Oct 06 '15 at 15:28
  • You just need to add/remove a blank article element in place of the newly positioned (absolute) element. See my answer below http://jsfiddle.net/dpL6amh2/ – deebs Oct 06 '15 at 15:33
  • @Marcos, no I can't, the articles list is generated on the fly, and also when the screen shrinks it does not contain three but only two articles. – PA. Oct 06 '15 at 15:40
  • @deebs don't quite get your intention, anyway the fiddle does no solve the problem, the box still jumps. – PA. Oct 06 '15 at 15:43
  • @charlietfl yes? I do? why can it be? I just change the styling, not the DOM – PA. Oct 06 '15 at 15:44
  • 1
    position absolute takes elements out of the document flow – charlietfl Oct 06 '15 at 15:50
  • @PA I didn't understand your initial issue - I thought you didn't want the other boxes (not the selected boxes) to move out of their original position. I added to Rick's solution and came up with this: http://jsfiddle.net/guhcwoy1/ – deebs Oct 06 '15 at 16:02

4 Answers4

3

Using the solution from @Rick (minus the css top edit) and then toggling an additional element to keep other elements in place, this should do what is needed: Fiddle

  $("article").click(function() { 
        $(this).toggleClass("expanded"); 
        if ($(this).hasClass("expanded"))
        {
            $(this).before("<article class='blank'>&nbsp;</article>");
        }
        else
        {
            $(this).prevAll('.blank').first().remove();
        }
  });

To explain further, when the element is clicked:

if ADDING the class 'expanded', then this will also add a blank article element (before) as a placeholder to keep the flow consistent. This is important because when the element with class 'expanded' becomes position: absolute it is removed from the normal flow of the content.

if REMOVING the class 'expanded', then this will also remove the blank article placeholder element. The prevAll function looks through all previous elements with the class 'blank' and then takes the first() one and removes it. Because it was inserted 'before', this is guaranteed to remove the correct blank article placeholder.

deebs
  • 1,390
  • 10
  • 23
  • Please say more about the `prevAll()` method. Include a simplified example if possible. – Alexander Dixon Oct 06 '15 at 16:13
  • prevAll() method looks through all of the previous elements (in this case with the class "blank"). This solution uses the first() differently, but may explain more in detail: http://stackoverflow.com/questions/2310270/jquery-find-closest-previous-sibling-with-class – deebs Oct 06 '15 at 16:22
2

When position:absolute is set on an <article> element, that takes it out of the normal content flow, and causes the offset. We can correct it by adding an empty <article> as a placeholder when the click triggers, and removing it when click again.

var open = false;

jQuery("article").click(function () {
    open = !open;

    if (open) {
        $(this).addClass("expanded");
        $(this).before("<article class='holder'>&nbsp;</article>");
    } else {
        $("article").removeClass("expanded");
        $(".holder").remove();
    }
});

p.s. I'm not that good at jQuery, any suggestions are welcome.

jsfiddle

Stickers
  • 75,527
  • 23
  • 147
  • 186
  • I'm accepting this one, because it helps understand the reason and solves the root cause, eventhough I am implementing a slightly different solution. – PA. Oct 06 '15 at 16:43
1

I can't think of a pure CSS solution, but since you're using jQuery anyway, simply hard-code the expanded element's top:

$("article").click(function() { 
  $(this).css('top', $(this).position().top);
  $(this).toggleClass("expanded"); 
});

Fiddle

The top style will be ignored once the expanded class is removed.

Rick Hitchcock
  • 35,202
  • 5
  • 48
  • 79
  • That's not a pure css solution, but it's simple enough for my needs. Also I like it, because it may help me with another little nasty css problem – PA. Oct 06 '15 at 15:47
  • with this solution when you click on "3", the numbered articles below jump up one position each. Is that okay still? I didn't understand the issue initially but now I am starting to. – deebs Oct 06 '15 at 15:51
  • This uses @Rick's solution with added jQuery to keep other articles in place: http://jsfiddle.net/fn2zv8va/ – deebs Oct 06 '15 at 15:57
-1

Try this

 <section>
    <article>1</article>
    <article>2</article>
    <article>3</article>
    </section>
    <section>
    <article>4</article>
    <article>5</article>
    <article>6</article>
    <section>
    <section>
    <article>7</article>
    <article>8</article>
    <article>9</article>
    </section>

    section {
        position:relative;
    }

    article { 
        width: 30%;
        min-width: 200px;
        min-height: 200px;
        display: inline-block;
        border: 1px solid black;
    }

    .expanded {
        width: 100%;
        background-color:#eef;
        left:0px;
        top:0;
        position:absolute;
        transition: 0.2s linear;
    }

    // if you want others to close while expanding
    $("article").click(function(){ 
       $('article').removeClass("expanded");
        $(this).toggleClass("expanded"); 
    });


// esle if you want everything to be expanded
   $("article").click(function(){ 
        $(this).toggleClass("expanded"); 
    });
faisal
  • 11
  • 3
  • Hi faisal, a valiant effort, however, you would have done better explaining your goal and addressing specifically the problem. Also, you can use free tools such as jsFiddle to provide an example. I won't downvote but others might. – Alexander Dixon Oct 06 '15 at 16:15