Select last sibling in each group of siblings - css

So I want to select the last sibling in a group of elements, but there are more than one group in the parent container.
<div class="wrapper">
<div class="select"></div><!-- padding-top -->
<div class="select"></div>
<div class="select"></div><!-- padding-bottom -->
<p>Some text</p>
<div class="select"></div><!-- padding-top -->
<div class="select"></div>
<div class="select"></div>
<div class="select"></div>
<div class="select"></div><!-- padding-bottom -->
<div>
So in this case, for every clump of .select elements, I need to add padding-top to the first one and padding-bottom to the last one. The tricky part is that the clump of .select elements can be infinitely large/small, but the first and last elements need padding.
This example works for the top padding...
// add padding-top to all elements
.select {
padding-top: 1em;
}
// remove it for general direct siblings
.select + .select {
padding-top: 0;
}
// this will only add to the last .select in the parent container,
// not the last in each clump of .select elements
.select + .select:last-of-type {
padding-bottom: 1em;
}
But the bottom padding for the last element in the clump is what I'm having issues with.
I can't add wrapper elements because this is pseudo generated code. JS would also make this a fairly straightforward solution, but I'd rather exhaust all of my CSS only solutions first.
Edit: The HTML structure is 100% arbitrary as it will be generated by the user in a WYSIWYG. However, there will be some sections of .select elements next to each other.

.wrapper>*:not(.select) + .select, .wrapper>.select + *:not(.select) {
margin-top: 1em;
}
.wrapper>.select:last-child {
margin-bottom: 1em;
}
If positioning was not the issue, and setting a margin-top on the next element doesn't do it (for example you have a background on .select and you actually need bottom padding on the last item in the group), well... you can't select the previous sibling with CSS.
So here's a solution using jQuery:
$('.wrapper>*:not(.select)').each(function() {
$(this).prev(".select").css({
'padding-bottom': '20px'
})
})
body {
margin: 0;
}
.wrapper {
padding: 20px;
}
.select {
background-color: #eee;
border-bottom: 1px solid white;
}
/* ignore CSS above, it's for coloring and padding so you see elements */
.select {
padding-top: 20px;
}
.select ~ .select {
padding-top: 0;
}
*:not(.select) + .select {
padding-top: 20px;
}
.wrapper>.select:last-child {
padding-bottom: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="select">select</div>
<!-- padding-top -->
<div class="select">select</div>
<div class="select">select</div>
<!-- padding-bottom -->
<p>Some text</p>
<div class="select">select</div>
<!-- padding-top -->
<div class="select">select</div>
<div class="select">select</div>
<div class="select">select</div>
<div class="select">select</div>
<!-- padding-bottom -->
</div>

Old question, I know, but I just had the same problem so thought this might be helpful for someone. Using :not() worked for me; I used borders instead of paddings for the example so it's more visible.
.wrapper * {
margin: 0;
padding: 0;
}
.select {
border-top: 30px solid #f00;
}
.select:last-of-type {
border-bottom: 30px solid #f00;
}
.select + .select {
border-top: 0;
}
.select + :not(.select) {
border-top: 30px solid #f00;
}
<div class="wrapper">
<div class="select">Select 1</div><!-- padding-top -->
<div class="select">Select 2</div>
<div class="select">Select 3</div><!-- padding-bottom -->
<p>Some text</p>
<div class="select">Select 4</div><!-- padding-top -->
<div class="select">Select 5</div>
<div class="select">Select 6</div>
<div class="select">Select 7</div>
<div class="select">Select 8</div><!-- padding-bottom -->
<div>

Is the structure always 2 groups of div separated by a p?
And is the padding meant to create space at top/bottom of each group?
And if so, would margin be okay instead?
Then here is a sample doing like so.
.wrapper div:first-child,
.wrapper p {
margin-top: 20px;
}
.wrapper div:last-child,
.wrapper p {
margin-bottom: 20px;
}
/* just for coloring making it visible */
.wrapper {
background-color: #666;
border: 1px solid black;
}
.wrapper p,
.select {
background-color: #aaa;
border: 1px solid white;
}
<div class="wrapper">
<div class="select">1</div><!-- padding-top -->
<div class="select">2</div>
<div class="select">3</div><!-- padding-bottom -->
<p>Some text</p>
<div class="select">1</div><!-- padding-top -->
<div class="select">2</div>
<div class="select">3</div>
<div class="select">4</div>
<div class="select">5</div><!-- padding-bottom -->
<div>
If it needs to be padding and you don't want to use script, this might work.
.wrapper div:first-child {
padding-top: 20px;
}
.wrapper div:last-of-type {
padding-bottom: 20px;
}
/* just for coloring making it visible */
.wrapper {
border: 1px solid black;
background-color: #666;
}
.wrapper p,
.select {
background-color: #aaa;
border: 1px solid white;
}
<div class="wrapper">
<div class="select">1</div>
<div class="select">2</div>
<div class="select">3</div>
<p>Some text</p>
</div>
<div class="wrapper">
<div class="select">1</div>
<div class="select">2</div>
<div class="select">3</div>
<div class="select">4</div>
<div class="select">5</div>
</div>

I don't think you need to touch the .select elements, just add padding top and bottom to the .wrapper, and margins top and bottom to the p

Related

Overlap outlines in css

I have an HTML structure with many divs next to each other or below each other that all have an outline. The problem is, these outlines do not overlap, but are shown next to each other (or on top of each other). To illustrate, this is what happens:
This is my code, with added nth-child() selectors to clearly show the issue:
.wrapper {
/* getting rid of the 'inline-block whitespace' */
font-size: 0;
white-space: nowrap;
}
.cell {
display: inline-block;
font-size: 2rem;
padding: 2px;
width: 100px;
}
.cell:nth-child(even) {
outline: 6px solid blue;
}
.cell:nth-child(odd) {
outline: 6px solid red;
}
<div class="wrapper">
<div>
<div class="cell">
one
</div>
<div class="cell">
two
</div>
</div>
<div>
<div class="cell">
three
</div>
<div class="cell">
four
</div>
</div>
</div>
My question is: How to make these outlines overlap so no 'doubles' are shown?
Update: using half the margin of the width of the outline on the cells does not always work when the outline width is 1px. For example, when the padding of .cell is 4px this is the result (when you zoom in you will see the two lines).
Update2: it seems this is a bug with Firefox on a 4k display. Running this in Firefox on a display with a HD resolution or in another browser (tested Chrome) works.
apply a margin equal to half the outline:
.wrapper {
/* getting rid of the 'inline-block whitespace' */
font-size: 0;
white-space: nowrap;
}
.cell {
display: inline-block;
font-size: 2rem;
padding: 2px;
width: 100px;
margin: 3px; /* added */
}
.cell:nth-child(even) {
outline: 6px solid blue;
}
.cell:nth-child(odd) {
outline: 6px solid red;
}
<div class="wrapper">
<div>
<div class="cell">
one
</div>
<div class="cell">
two
</div>
</div>
<div>
<div class="cell">
three
</div>
<div class="cell">
four
</div>
</div>
</div>
Or use margin on one side:
.wrapper {
/* getting rid of the 'inline-block whitespace' */
font-size: 0;
white-space: nowrap;
}
.cell {
display: inline-block;
font-size: 2rem;
padding: 2px;
width: 100px;
margin:0 6px 6px 0; /* added */
}
.cell:nth-child(even) {
outline: 6px solid blue;
}
.cell:nth-child(odd) {
outline: 6px solid red;
}
<div class="wrapper">
<div>
<div class="cell">
one
</div>
<div class="cell">
two
</div>
</div>
<div>
<div class="cell">
three
</div>
<div class="cell">
four
</div>
</div>
</div>

Horizontally align div with an element outside its parent

This image shows what I am trying to do.
Basically, I have a header and footer inside the body. I have a div1 inside a header which has a size that can vary. I want to align div2, which is inside the footer, so that its right border is matches the right border of div1.
The following HTML can explain the structure.
<body>
<div id="header">
<div id="div1">
</div>
</div>
<div id="footer">
<div id="div2">
</div>
</div>
This would be the css.
#div1 {
overflow: auto;
display: grid;
float: start;
}
#div2 {
width: 20px;
// ??????
}
There's no float: start. You just be better off having a common container, as how it is in Bootstrap and other frameworks to "contain" your code. So your page might be rendered well this way:
body {
font-family: 'Segoe UI';
background: #ffa500;
}
#header {
background-color: #fcc;
padding: 10px;
}
#footer {
background-color: #f99;
padding: 10px;
}
.container {
max-width: 65%;
overflow: hidden;
}
#div1 {
padding: 10px;
background-color: #99f;
}
#div2 {
padding: 10px;
background-color: #ccf;
float: right;
width: 50%;
}
<div id="header">
<div class="container">
<div id="div1">
div1
</div>
</div>
</div>
<div id="footer">
<div class="container">
<div id="div2">
div2
</div>
</div>
</div>
Preview

Align elements relative to each other

Basically I'm wondering if you can position 2 elements relative to each other.
I have a h1 and h2 inside a div, I want to align the h2 to the right side of the h1
html
<header>
<div>
<h1>Header with some text</h1>
<h2>Other header</h2>
</div>
<div>
</div>
<div>
</div>
</header>
css
header {
width: 960px;
}
div {
width: 318px;
float: left;
border: 1px solid red;
min-height: 200px;
}
h1, h2 {
font-size: 16px;
}
The simplest solution is to wrap the headings in an extra inline-block div and the apply text-align:right.
.parent {
width: 80%;
border: 1px solid red;
}
.wrap {
display: inline-block;
text-align: right;
}
<div class="parent">
<div class="wrap">
<h1>
I'm a really long h1 tag
</h1>
<h2>
Short h2 tag
</h2>
</div>
</div>
use this code
.some_class > * {
display:inline-block;
}
<div class="some_class">
<h1>some text</h1>
<h2> Some other text </h2>
</div>

Draw a static line between two divs

I have three divs on the same line and want to connect them with a line:
Unfortunately, every way I tried collided with the method of display, e.g. inline-block and vertically aligned spacer divs of height 50% with bottom-border.
http://codepen.io/anon/pen/QwOOZp
if it stands on 1 line, you could add pseudo element and filter first and last box, to draw or not a line aside.
div.boxItem {
display: inline-block;
border: 1px solid black;
padding: 1em;
margin-right: 5em;
position:relative
}
.boxItem:before,
.boxItem:after
{
content:'';
width:5em;/* size of your margin */
border-bottom:1px solid;
position:absolute;
top:50%;
}
:after {
left:100%;
}
:before {
right:100%;
}
.boxItem:first-of-type:before,
.boxItem:last-of-type:after {
display:none;
}
.myBox {
white-space:nowrap;
/* */ text-align:center;
}
body {
}
<div class="myBox">
<div class="boxItem">1</div>
<div class="boxItem">2</div>
<div class="boxItem">3</div>
<div class="boxItem">4</div>
</div>
<div class="myBox">
<div class="boxItem">1</div>
<div class="boxItem">2</div>
<div class="boxItem">3</div>
</div>
<div class="myBox">
<div class="boxItem">1</div>
<div class="boxItem">2</div>
</div>
<div class="myBox">
<div class="boxItem">1</div>
</div>
fork of your pen
Try this:
div.boxItem {
display: inline-block;
border: 1px solid black;
padding: 1em;
}
div.line {
display: inline-block;
border-top: 1px solid black;
width: 2em;
}
<div class="boxItem">1</div><!--
--><div class="line"></div><!--
--><div class="boxItem">2</div><!--
--><div class="line"></div><!--
--><div class="boxItem">3</div>
Note: I used <!-- and --> to comment out the white space ensuring the line actually touches the divs. More info on that bit: https://stackoverflow.com/a/19038859/2037924
EDIT: Same in CodePen, for the case you like that more for some reason: https://codepen.io/anon/pen/wBPPRz
You could add a div with the width of your margin:
<div class="boxItem">1</div>
<div class="emptyDiv"></div>
<div class="boxItem">2</div>
<div class="emptyDiv"></div>
<div class="boxItem">3</div>
CSS:
div {
display: inline-block;
}
div.emptyDiv{
border: 1px solid black;
width:25em;
}
div.boxItem {
border: 1px solid black;
padding: 1em;
}

Keeping div's width same as wrapper, but making the background full width

The image shows what I'm trying to accomplish. All 3 divs are contained in a wrapper that's 800px. But the second div's background extends the full width of the body.
I have a solution nearly identitical to the one by patkay.
My HTML:
<div class="outer-wrapper">
<div class="inner-wrapper">
<div class="content">Content 1...</div>
</div>
<div class="inner-wrapper noted">
<div class="content">Content 2...</div>
</div>
<div class="inner-wrapper">
<div class="content">Content 3...</div>
</div>
</div>
And my CSS:
.outer-wrapper {
width: 100%;
outline: 1px dotted blue;
}
.inner-wrapper {
width: inherit;
}
.inner-wrapper.noted {
background-color: gray;
}
.content {
width: 600px;
margin: 10px auto;
outline: 1px dotted red;
}
Fiddle reference: http://jsfiddle.net/audetwebdesign/Nbu7G/
Essentially, I use the .outer-wrapper to set control the overall width, and then inherit the width to the .inner-wrapper which is used to set the background color through an extra class call .noted.
The inner-most container .content has the fixed width (for example, 600px).
The extra markup could be clean-up semantically using HTML5 tags, but this pattern gives you a lot of hooks to use background images and so on.
One way you can do this is to have three separate div's that are all aligned centrally on the inside, have full width backgrounds and are stacked on top of each other.
<div class="top">
<div class="wrap">
<p>Some content</p>
</div>
</div>
<div class="mid">
<div class="wrap">
<p>Some content</p>
</div>
</div>
<div class="bottom">
<div class="wrap">
<p>Some content</p>
</div>
</div>
The CSS is:
body {
text-align: center;
}
.top, .bottom {
background: #aaa;
width: 100%;
}
.mid {
background: #616161;
width: 100%;
}
.wrap {
width: 800px;
margin: 0 auto;
padding: 5px;
}

Resources