I have several same HTML elements going one after another:
<span>1</span>
<span>2</span>
<span>3</span>
I'm looking for the best way of adding space between the elements using CSS only
[no space] [1] [space 10px] [2] [space 10px] [3] [no space]
Additionally:
Please write down browser compatibility of your receipts
I don't want to use any additional HTML markup like
<span></span> <span></span> <span class="last_span"></span>
I don't want to use tables.
I want the first and last span to be targeted automatically by CSS.
I don't want to use JavaScript.
Optional requirement: last span can be not last child of the parent tag, but it will be the last span of the parent tag. Spans do not have any other tags between them.
A good way to do it is this:
span + span {
margin-left: 10px;
}
Every span preceded by a span (so, every span except the first) will have margin-left: 10px.
Here's a more detailed answer to a similar question: Separators between elements without hacks
Just use margin or padding.
In your specific case, you could use margin:0 10px only on the second <span>.
Here's a nice CSS 3 solution (JSFiddle):
span {
margin: 0 10px;
}
span:first-of-type {
margin-left: 0;
}
span:last-of-type {
margin-right: 0;
}
Advanced element selection using selectors like :nth-child(), :last-child, :first-of-type, etc. is supported since Internet Explorer 9.
Add these rules to the parent container:
display: grid
grid-auto-flow: column
grid-column-gap: 10px
A good reference: CSS Reference - A free visual guide to CSS
Browser compatibility: Browser Support for CSS Grid Layout
You can style elements with excluding the first one, just in one line of code:
span ~ span {
padding-left: 10px;
}
There isn't a need to change any classes.
You can take advantage of the fact that span is an inline element:
span{
word-spacing: 10px;
}
However, this solution will break if you have more than one word of text in your span.
span:not(:last-child) {
margin-right: 10px;
}
You can write like this:
span{
margin-left: 10px;
}
span:first-child{
margin-left: 0;
}
You should wrap your elements inside a container, use new CSS 3 features like CSS grid, a free course, and then use grid-gap:value that was created for your specific problem.
span{
border: 1px solid red;
}
.inRow{
display: grid;
grid-template-columns: repeat(auto-fill, auto);
grid-gap: 10px /* This adds space between elements, only works on grid items */
}
.inColumn{
display: grid;
grid-template-rows: repeat(auto-fill, auto);
grid-gap: 15px;
}
<div class="inrow">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<div class="inColumn">
<span>4</span>
<span>5</span>
<span>6</span>
</div>
If you want to align various items and you like to have the same margin around all sides, you can use the following. Each element within container, regardless of type, will receive the same surrounding margin.
.container {
display: flex;
}
.container > * {
margin: 5px;
}
If you wish to align items in a row, but have the first element touch the leftmost edge of container, and have all other elements be equally spaced, you can use this:
.container {
display: flex;
}
.container > :first-child {
margin-right: 5px;
}
.container > *:not(:first-child) {
margin: 5px;
}
<span> is an inline element, so you can’t make spacing on them without making it block level.
Try this:
Horizontal
span{
margin-right: 10px;
float: left;
}
Vertical
span{
margin-bottom: 10px;
}
It is compatible with all browsers.
Or, instead of setting margin and then overriding it, you can just set it properly right away with the following combination:
span:not(:first-of-type) {
margin-left: 5px;
}
span:not(:last-of-type) {
margin-right: 5px;
}
span.middle {
margin: 0 10px 0 10px; /* top right bottom left */
}
<span>text</span> <span class="middle">text</span> <span>text</span>
Related
I'm very confuses about float.
.two should be on the right of .one
but .two just below .one
div {
width: 100px;
background: #FF9;
}
;
.theone {
float: left;
font-size: 20px;
}
<div class="theone">one</div>
<div class="theright">two</div>
into div css add display:inline-block;
div{
display: inline-block;
}
.theright {
float: left;
font-size: 20px;
}
add that in, if you want 2 divs to be next to eachother it is best to have them both float right.
additionally you could replace .theone with .theone,.theright
A div has display: block by default.
You probably want to set another display type to your divs.
div { width: 100px; background: #FF9; display: inline; }
.theone { float: left; font-size: 20px; }
See jsFiddle
I'll try and make a detailled and explained answer. A floating element floats from its initial position in the flow. Basically, the floating effect affects only elements declared after it on the HTML structure.
In your case, the right-floating element is declared after the non-floating one. So it is normal theright appears below theone and you don't see the floating effect.
To make an element float on the right of another, you must declare it before this another. Like this :
<div class="theright">two</div>
<div class="theone">one</div>
<style>
.theright {
float: right;
}
</style>
Note that for this to work, theright element needs to be larger than theone. Otherwise, theone will mask entirely theright pushing its content out of the box. It is so because a floating element gets out of the flow and hovers over the other elements, which contents "avoid" the floating blocks.
There are many other ways to obtain the same result with a different approch :
make theone float on the left instead (leaving theright as a basic block element)
make both elements inline-blocks and give them appropriate widths
for two elements only, it is not necessary, but if you need 3 or more elements side by side, you can make them all float on the left (or on the right declaring them in reverse order, depending on the final layout you want)
etc.
div {
width: 100px;
background: #FF9;
display: inline-block;
}
;
.theone {
float: left;
font-size: 20px;
}
<div class="theone">one</div>
<div class="theright">two</div>
By default div's have display value set to "block" which means they "begin from next line".
If you add display: inline-block property for all divs, then you can add float: left for any div to make it first.
no javascript and no screen width media queries
I am trying to find a css-only way to achieve the situation depicted in below image. I couldn't find a way to create the following:
a line of blocks (inline blocks or floated blocks) with variable width, aligned to the right of the line using float:right or right text align
elements that don't fit on the line, wrap to the next line. All elements after the first line have their own line.
I've been experimenting around with several strategies to no avail, I have a feeling that flexbox might help but I'm not very experienced with flexbox and couldn't find a way to use it.
A few things that I have tried:
try to put the elements' content in a :before pseudo element, using content:attr(data-content). The element itself would have no width. On the next line there would be a left floating element with a width of 99.9% that pushes each element on a next line. The problem with this is that the elements on the first line should maintain their normal width and I didn't find a way to do that. The :first-line pseudo-selector is limited to words on the line and doesn't work for inline containers on the line
Alternative to above method: also add :after pseudo elements which are absolutely positioned and have the same content as the :befores. The :before elements would only show on the first line and don't wrap, the :after elements would form the vertical list on the right. Also with this way I walked into a dead end.
UPDATE:
I made a (less) fiddle that works when the elements' widths are fixed and equal. Unfortunately fixed width, so not yet what I want to achieve. If you want to help me you could perhaps use this as a starting point. I put the content in a :before so perhaps it could overflow the element and somehow fix the element width to auto.
currently CHROME only: http://jsfiddle.net/2px3b63j/7/
html:
<div class="pusher"></div>
<nav>
<a data-title="First" href="#"></a><a data-title="Second" href="#"></a><a data-title="Third" href="#"></a><a data-title="Fourth" href="#"></a><a data-title="Fifth" href="#"></a>
</nav>
less:
#h: 3em;
#w:6em;
* {
margin: 0;
padding: 0;
}
body {
font: 0.9rem sans-serif;
background: #666;
}
.pusher {
float: left;
width: ~"calc(100% - " (#w * 1.01) ~")";
height: #h * 6;
-webkit-shape-outside: polygon(0 #h, 100% #h, 100% 100%, 0 100%);
}
nav {
position: relative;
text-align: right;
background: white;
height: #h;
line-height:0;
a {
position: relative;
text-align:center;
width: #w;
max-width: 100%;
display: inline-block;
background: white;
text-decoration: none;
color: #333;
font-weight: bold;
height: #h;
line-height: #h;
&:before {
content: attr(data-title);
}
}
}
LINK TO ANSWER: https://jsfiddle.net/ky83870x/1/ doesn't work in Internet Explorer but I assume it works in Edge. If anyone can find a way to make it work in IE, I will be very interested to know
One posibility to get your output using flex box.
Make the flexbox so narrow that any child will fit. That forces the children to go one in a row.
Add a pseudo element before the first child to force an extra margin.
Justify the flex as needed
And place the flex to the right, because now everything is to the left.
The elements are color coded to see easily what is happening
.container {
display: flex;
flex-flow: row wrap;
border: solid 1px red;
width: 10px;
left: 500px;
position: absolute;
justify-content: flex-end;
}
.container div {
font-size: 20px;
margin: 5px;
background-color: lightblue;
display: inline-block;
flex-basis: auto;
flex-shrink: 0;
}
.container:before {
content: "";
margin-left: -500px;
flex-basis: 10px;
background-color: yellow;
height: 6px;
}
<div class="container">
<div>Lorem</div>
<div>Ipsum dolor sit amet</div>
<div>Consectetur adipisicing elit</div>
<div>Unde saepe</div>
<div>Placeat neque mollitia</div>
<div>Accusamus fuga</div>
<div>Lorem</div>
<div>Ipsum dolor sit amet</div>
<div>Consectetur adipisicing elit</div>
<div>Unde saepe</div>
<div>Placeat neque mollitia</div>
<div>Accusamus fuga</div>
</div>
I have 4 successive divs:
<div class="container">
<div class="child">A</div>
<div class="child">B</div>
<div class="child">C</div>
<div class="child">D</div>
</div>
Assuming each child div has varying content, of different heights, and a margin added for clarity, it displays as follows:
Without changing the HTML in any way (no adding classes to the divs, no adding intermediary column divs), I would like to achieve this layout:
The order in which the divs are placed does not matter much.
I've tried things along the lines of:
.child { width: 50%; }
.child:nth-child(even) { float: left; }
.child:nth-child(odd) { float: right; }
But the alignnments are off. Does any CSS wizard have an idea?
Does this work?
DEMO
.container {
width:220px; /* (child width)x2 + (child margin)x4 */
}
.child {
margin:5px;
background-color:#FF0080;
width:100px;
}
.child:nth-child(even) {
float: left;
}
.child:nth-child(odd) {
float: right;
}
Well you could use CSS columns, which has good partial support across browsers (primarily prefixed though), but full support is not so great.
Give them a try:
.container {
-webkit-column-width: 250px;
-moz-column-width: 250px;
column-width: 250px;
width: 520px;
background: yellow;
}
.child {
background: red;
margin-bottom: 10px;
display: inline-block;
width: 100%;
}
Take a look at this jsfiddle for a demonstration: http://jsfiddle.net/xwwe3/ (complete with My First Colours to demonstrate what is happening).
The columns are set to 250px wide, which I found the .child didn't obey until given display: inline-block; width: 100%;. Then the width of .container is set to 520px to give the columns a gutter width of 10px with two columns (250 * 2 + 10 = 520)
So depending on whether you think the support is acceptable for your use case is up to you. Tweaking the heights of the .child elements does make some weird stuff happen, but I'd suggest you read up further on CSS columns and try and work out what is going there.
Alternatively, jQuery masonry is a popular way of achieving this.
I'm trying create a balanced (2-) column-layout.
The content is not text but blocks and varies in height.
The content should be placed alternatingly left and right, as long as "left" and "right" have (roughly) the same height..
I.e. in this image:
The space between 1 and 3's shouldn't be there.
Or in this image:
the 2's should stand alone on the right side and the 1, 3's and 4 should stand on the left side (without space between them).
I tried using "floating <li>'s" like this:
HTML:
<ol class="context">
<li class="gruppe">1</li>
<li class="gruppe">2.0<br />2.1</li>
<li class="gruppe">3.0<br />3.1</li>
<li class="gruppe">4</li>
</ol>
CSS:
ol.context
{
border: 1px solid #048;
list-style: none;
margin: 0;
padding: 0 0 8px 0;
overflow: auto;
}
li.gruppe
{
background: #048;
color: white;
float: left;
font: bold 32px Arial, sans-serif;
margin: 1px;
text-align: center;
width: calc(50% - 2px);
}
(See attempt 1 and attempt 2)
I have also tried to use column's (column-count: 2; column-fill: auto;) but this does not fill the columns left-to-right first. (It fills top-to-bottom first.)
Is this even possible without JavaScript?
I would say this is not possible without JS. Here is a fiddle I made based on an article from Ben Holland. At least to me looks like what you are after.
http://jsfiddle.net/QWsBJ/2/
HTML:
<body onload="setupBlocks();">
<div class="block">
<p>***Content***</p>
</div>
<div class="block">
<p>***Content***</p>
</div>
<div class="block">
<p>***Content***</p>
</div>
<div class="block">
<p>***Content***</p>
</div>
<div class="block">
<p>***Content***</p>
</div>
</body>
CSS:
.block {
position: absolute;
background: #eee;
padding: 20px;
width: 300px;
border: 1px solid #ddd;
}
JS:
var colCount = 0;
var colWidth = 0;
var margin = 20;
var blocks = [];
$(function(){
$(window).resize(setupBlocks);
});
function setupBlocks() {
colWidth = $('.block').outerWidth();
colCount = 2
for(var i=0;i<colCount;i++){
blocks.push(margin);
}
positionBlocks();
}
function positionBlocks() {
$('.block').each(function(){
var min = Array.min(blocks);
var index = $.inArray(min, blocks);
var leftPos = margin+(index*(colWidth+margin));
$(this).css({
'left':leftPos+'px',
'top':min+'px'
});
blocks[index] = min+$(this).outerHeight()+margin;
});
}
Array.min = function(array) {
return Math.min.apply(Math, array);
};
Updated: I believe this is almost impossible to achieve with CSS only. There are many different solutions, but they all require some compromises unless you are willing to use JavaScript or some server-side code.
Using CSS columns
Here's an alternate fiddle using reordered blocks. Here's a fiddle demo using CSS columns without reordering.
You can use CSS colunms to change your block flow to vertical unless you alter the order of their output. If you can output odd numbers first, then even numbers, you win.
<div class="wrapper">
<div class="block1">1</div>
<div class="block3">3</div>
<div class="block2">2</div>
<div class="block6">4</div>
</div>
.wrapper {
column-count: 2;
column-width: 100px;
-moz-column-width: 100px;
-webkit-column-width: 100px;
width: 260px;
}
div {
border: 1px solid #999;
display: inline-block;
margin: 10px;
width: 100px;
}
.block1 { height: 100px; }
.block2 { height: 130px; }
.block3 { height: 150px; }
.block4 { height: 100px; }
This solution is not compatible with IE9 and below.
Block Height Known
If you do know your block heights you can solve this problem by using absolute positioning.
block1 {
height: 100px;
position: absolute;
left: 0;
top: 0;
}
block2 {
height: 110px;
position: absolute;
left: 0;
top: 100px; /* The height of the div above it */
}
A big drawback is dynamic content; we seldom know block height. So this solution is very limited in its application unless you are willing to calculate the height block height.
If you are willing to use JS
Use a plugin like Masonry. Both in vanilla js or jQuery flavour.
Other Options
This leaves you with the following options that require some compromises.
Group your blocks into columns. See this Fiddle for a demo. This will alter the flow of your blocks to vertical, then horizontal.
Use display: inline-block; vertical-align: top; on your blocks. This will leave some white space below your blocks.
Force the height of your blocks, rendering this a non-issue. For blocks with additional content use the overflow property to allow in-block scrolling.
As others have commented, you could attempt to calculate the height of the blocks on the server.
You could try a mix of flex and float (only tested in Firefox/IE10 and safari 5.1.7 , cause to my own opinion, CSS is not your solution)
http://codepen.io/gcyrillus/pen/zgAiw
But, in any CSS case you choose, the best is to relay on the mansonry script.
CSS is not really adapted to this kind of layout. At this time you have many CSS method for layout and basicly: display and float.
You can easily use this together within your html tree structure but this methods are not meant to be mixed. A boxe will be floatting, an inline-level-box or block-level-box and each are suppose to interact in the flow.
Float, breaks a line before itself after a non floatting element or slides down untill it has enough room, that you dispatch right/left via CSS r not.
inline-block moves away from floatting elements and breaks a line if not enough room left, floatting elements among inline-blocks will keep breaking a line before floating.
Column CSS will fill columns with content one by one. see : http://codepen.io/gcyrillus/pen/AtazJ
Inline-flex elements seems to work with floatting elements ... but is it suppose to untill it's a validated rule ?
What seems to be wised to me , is to used a javascript for the layout expected and relay on float or display:inline-block + width as a fall back.
Last solution is to think this ahead on your server side and dispatch your items in 2 containers with another appropriate markup if that is possible ( no idea of your real life content dispatched in your ol li ).
The CSS for the FLEX test :
li.gruppe
{
background: #048;
color: white;
font: bold 32px Arial, sans-serif;
text-align: center;
box-sizing:border-box;
border-bottom:1px solid white;
border-bottom:1px solid white;
display: -webkit-inline-flex;
display: -moz-inline-flex;
display: -ms-inline-flex;
display: inline-flex;
width:50%;
}
li:nth-child(even){
float:right;
clear:right;
border-left:1px solid white;
margin-top:0;
}
EDIT: This is an interesting solution, but unfortunately it does not solve the problem that was asked for.
The solution I propose here puts subsequent elements into alternating columns, so: 1 -> left, 2 -> right, 3 -> left, 4 -> right, etc.
This is a interesting problem by itself, but not what was asked for.
Thanks to #Nils in the comments for pointing this out.
Original answer
Here is my attempt with flex!
https://jsfiddle.net/vqLr8t3e/
I am not sure if it works in IE11.
Code
.the-beginning {
background: green;
color: white;
font-weight: bold;
text-align: center;
cursor: pointer;
}
.the-end {
background: red;
color: white;
font-weight: bold;
text-align: center;
cursor: pointer;
}
.container-outer {
overflow: hidden;
}
.container {
display: flex;
flex-wrap: wrap;
flex-direction: column;
max-height: 19999px;
margin-top: -10000px;
}
.container > div {
width: 50%;
box-sizing: border-box;
border: 5px solid grey;
padding: 5px;
background: white;
order: 1;
}
.container > div:nth-child(odd) {
order: -1;
}
.container > div:nth-child(1),
.container > div:nth-child(2) {
margin-top: 10000px;
}
<div class="the-beginning">THE BEGINNING</div>
<div class="container-outer">
<div class="container">
<div>LEFT 0</div>
<div>RIGHT 0<br>RIGHT 0</div>
<div>LEFT 1<br>LEFT 1<br>LEFT 1</div>
<div>RIGHT 1</div>
<div>LEFT 2</div>
<div>RIGHT 2<br>RIGHT 2<br>RIGHT 2</div>
</div>
</div>
<div class="the-end">THE END</div>
Idea
Use flex-direction: column; and flex-wrap: wrap; on the container, and width: 50%; on the items, as a first step towards showing the items in columns.
Use order: -1; and order: 1 to sort odd and even elements into different columns.
Use a gratuitous margin-top: 10000px; on the first element of each column, and a max-height: 19999px; on the container, so that no two such items fit into one column. This will make sure each of these items starts in a new column. Compensate with a negative margin-top on the container. Cut it off with an outer container with overflow: hidden;.
I'm not sure if I got this right . .
"the 2's should stand alone on the right side and the 1, 3's and 4
should stand on the left side (without space between them)."
html:
<div id="box">
<div class="data">1</div>
<div class="data" style="float:right">2<br/>2<br/>2<br/>2</div>
<div class="data">3<br/>3</div>
<div class="data">4</div>
</div>
css:
#box {
width:100%;
height:auto;
float:left;
}
.data {
height:auto;
width:50%;
float:left;
background-color:#ccc;
border-bottom:solid 1px #000;
}
Fid:
http://jsfiddle.net/YdEW9/26/
This is pure css. Everything is floated left then gave inline-css to float:right on the div with (4) 2's
I kinda don't know how to set the inline-css without javascript. Server side maybe? but I doubt you can get the height of the elements.
Well anyway hope this helps.
PURE CSS SOLUTION:
Add the following to your css file:
ol.context li:nth-child(even) {
float: right;
}
DO NOT change your html or anything else.
Result in FF:
--
How it Works
Instead of floating all your elements "left" and creating gaps, we float each container according to the side/column the element they reside in.
I want a gap of say 30px; between all children of my div. E.g if I have:
<div id="parent">
<img ... />
<p>...</p>
<div>.......</div>
</div>
I want all of them to have a space of 30px; between them. How can I do this with CSS?
For an unknown amount of children you could use.
#parent > * {
margin: 30px 0;
}
This will add a top and bottom margin of 30px to all direct children of #parent.
But img is not displaying as block default, so you may use:
#parent > * {
display: block;
margin: 30px 0;
}
Vertical margins of block elements will be collapsed. But you will have margins at top and bottom of your parent div. To avoid that use the following code:
#parent > * {
display: block;
margin-top: 30px;
}
#parent > *:first-child {
margin-top: 0px;
}
This will only add top margin and removes that top margin for the first element.
The following css will work well
div > *:not(:last-child) {
display: block;
margin-bottom: 30px;
}
> selects all elements that are direct children of the div (so you don't get weird inner spacing issues), and adds a bottom margin to all that aren't the last child, using :not(:last-child) (so you don't get a trailing space).
display: block makes sure all elements are displayed as blocks (occupying their own lines), which imgs aren't by default.
You can easily do that with:
#parent > * + * {
margin-top: 30px;
}
This will be applied to all direct children except the first one, so you can think of it as a gap between elements.
Probably the easiest way is this:
#parent * {
margin-bottom: 30px;
}
or
#parent * {
margin: 15px 0;
}
Keep in mind, though, that this will get everything in #parent, including things inside the p and div tags. If you want just the direct children, you can use #parent > * (this is call the direct descendent selector) instead.
Keep in mind, <img> is an inline element by default, so you might need to do:
#parent img {
display: block;
}
for it to use the margins.
Use CSS gap property.
.parent_class_name{
gap: 30px;
}
The above CSS code will apply a gap/separation of 30px between children of the parent_class_name class.
Example: This code will apply 1rem gap between element (rows and columns).
<div class="gap_container">
<div>a</div>
<div>b</div>
<div>c</div>
</div>
.gap_container{
display: flex;
flex-direction: column;
gap: 1rem;
}
The gap property defines the size of the gap between the rows and columns. It is a shorthand for the following properties:
row-gap
column-gap
Apply row and column values separately.
gap: row-value column-value;
Learn more: w3school
Create a CSS class for them with code:
.BottomMargin
{
margin-bottom:30px;
}
And assign this class to parent's children using jQuery or manually like this:
<div id="parent">
<img class="BottomMargin" ... />
<p class="BottomMargin">...</p>
<div>.......</div>
</div>
the last one may not have one and this is also doable using jQuery.
You can try it by CSS standarts:
div > *{
margin-top:30px;
}
More info could be found here: http://www.w3.org/TR/CSS2/selector.html#child-selectors
Just put a top and bottom margin of 30px on your p element:
p { margin: 30px 0 30px 0; }
Note: the above will add this margin to all your p elements. To restrict to just this one, either add an inline style attribute:
<p style="margin: 30px 0 30px 0;">...</p>
or better use a class:
<p class="mypara">...</p>
and in css:
p.para { margin: 30px 0 30px 0; }
Btw, the notation here for margin is:
margin: top right bottom left;
Or you can individually specify top and bottom margins:
margin-top: 30px;
margin-bottom: 30px;
So you could have a class like this:
.bord { margin-bottom: 30px; }
and add this class to every element you want to have a margin-bottom of 30px:
<div class="bord">....</div>
Surest way is to add a class to all of the internal elements with the exception of the last one.
<style>
.margin30 {
margin-bottom: 30px;
}
<div id="parent">
<img class="margin30" ... />
<p class="margin30">...</p>
<div>.......</div>
</div>
This way, additional elements can just be tagged with the class. Remember that you can multiclass style elements by separating them within the class value in the tag with spaces, like so:
<img class="margin30 bigimage" ... />
Finally, you can attach the classes dynamically with Javascript (code off the top of my head, not tested, no sanity checks or error handling, ymmv etc.):
function addSpace(elementId) {
children = document.getElementById(elementId).childNodes;
for (i=0;i<(children.length - 1);i++)
children[i].className = "margin30 " + children[i].className;
}