Is it possible to implement vertical layout with CSS only, and not with HTML elements?
I have a list of divs inside one div. By default the next element is right to the last, when there's no place on right, it is placed below.
I'd like to achieve the same with CSS style settings. Is it possible?
By CSS-only I mean, we have div and its children, and do not add anything special such as:
line-breaking elements ( <br/>, <div style="clear:both;"/> )
UL tags
tables (yes, still used, f.g. JSF almost exclusively based on them)
So:
<div id="menu">
Page 1
Page 2
Page 3
</div>
And CSS implementing vertical layout:
#menu { ??? }
#menu a { ??? }
Is there a ??? that I could use to achieve what I want?
Display anchor tags as block elements.
#menu a {
display: block;
}
Do you mean something like this?
http://jsfiddle.net/7Y9jS/
#menu {
width: 300px;
}
#menu a {
display: block;
background: #ccc;
color: #000;
padding: 10px 0;
text-align: center;
margin-bottom: 2px;
}
<div id="menu">
Page 1
Page 2
Page 3
</div>
set display block to a
#menu a {
display: block;
}
use float left
#menu a {
float:left;
}
and then add the class group to your #menu
.group:before,
.group:after {
content: "";
display: table;
}
.group:after {
clear: both;
}
.group {
zoom: 1; /* For IE 6/7 (trigger hasLayout) */
}
Related
I am using react-indiana-drag-scroll, and I am doing a Horizontal scroll, but the last item ( the 30th) 's right red shadow cannot show on screen
I tried to add padding/ margin/ border, still does not work.
sandbox: https://codesandbox.io/s/react-indiana-drag-scroll-default-forked-1xcxt
It's not the issue of react-indiana-drag-scroll. It's the peculiarity of browsers behavior [1], [2].
There are many different solutions to solve your exact problem.
Emulate margin by :after pseudo-element (example):
.container:after {
content: "";
flex: 0 0 10px;
}
.row:last-child {
margin-right: 0;
}
Use inline-block (example):
.container {
display: block;
white-space: nowrap;
}
.row {
...
margin: 10px;
display: inline-block;
}
Other solutions could be found by the links above.
I am trying to create a multi-tiered menu with a breadcrumb navigation, without using javascript. I have come across loads of pure css menus and breadcrumbs, but never combined and working together. Here’s a design of what I’m trying to achieve (click on the ‘more’ hamburger menu):
https://invis.io/857RUKE6M
And this is what I have so far in my html/css (see codepen link below). Please forgive the crude/hacky code. At this point I am simply testing ideas, I will simplify and beautify my code once I’ve found a solution.
http://codepen.io/jessbenz/pen/LZWjjz
Here's a code snippet, but please look at the codepen link above to get a better feel:
<div class="smart-nav">
<input type="radio" id="bread-home" class="breadcrumb" name="bread" />
<input type="radio" id="bread-women" class="breadcrumb" name="bread" />
<input type="radio" id="bread-womens-clothing" class="breadcrumb" name="bread" />
<div class="smart-nav-panels">
<ul id="home">
<li>
<input type="radio" name="first">
<label>1 Women</label>
<ul id="women">
<li>
<input type="radio" name="second">
<label>1.1 Women's Clothing</label>
<ul id="womens-clothing">
<li>
<label>1.1.1 Women's Shirts</label>
</li>
</ul>
</li>
</ul>
</li>
<li>
<input type="radio" name="first">
<label>2 Men</label>
<ul id="men">
<li>2.1 Men's Shirts</li>
</ul>
</li>
</ul>
</div>
</div>
and my sass:
.breadcrumb:checked ~ .smart-nav-panels ul {
display: none;
}
#bread-home:checked ~ .smart-nav-panels > ul {
display: block;
}
#bread-women:checked ~ .smart-nav-panels {
#home, #women {
display: block;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#home, #women, #womens-clothing {
display: block;
}
}
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child {
display: block;
}
.smart-nav-panels {
margin: 0;
padding: 0;
ul {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background: lightgrey;
}
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
> ul:first-child {
ul {
left: 100%;
}
}
li {
input + label + ul {
display: none;
}
input:checked + label + ul {
display: block;
// left:0;
}
}
}
input:checked ul {
display: block;
}
If you click through the women's clothing in my codepen sample, you’ll see I am half way there with achieving what I need. The top horizontal radio buttons represent the breadcrumbs and vertical radio buttons within the gray block represent the tier menu. The problem comes in when I select a breadcrumb radio. The correct slide is displayed but then if I select a radio within the menu again, it isn’t displaying because my breadcrumb css is taking preference and hiding the relevant content. I guess herein lies the issue with not using javascript. How do I make both my navigations aware of each other with pure css? It could be that this approach of combining two radio navigations is the incorrect one. I really hope someone can share their wisdom. :)
Thanks in advance
You don't shy away from a challenge, do you? :)
Before I launch into any more detail, I would say that the short answer is "build a static site". In other words, assuming one of your design constraints is "no javascript", move the problem to a place where you do have the luxury of using decision logic / code to make it easier to solve (ie: the server).
Even if you manage to solve this problem (and I'm not sure it's possible given the constraints of HTML/CSS), the next problem you're going to have is attaching any sort of behaviour to it all. You're going to want to load specific content based on the menu selection, and the only way you're going to do that is with:
a javascript event, or
a static link (anchor element, hence the 'why' behind my short answer)
One could load all of the content and perhaps find a way to display it conditionally, but then the question is "how deep does the rabbit hole go?". Plus if you're building for feature phones and/or slow connections, loading all of the content is going to have a negative impact on the user experience.
Having said all of that, I managed to simplify the CSS slightly and fix a bug with the display of subcategories (see comments inline). Note that only the 'Women' category behaves as expected as there are styles missing for 'Men' & 'Kids'.
.container {
position: relative;
width: 360px;
height: 480px;
border: 1px solid black;
margin: 20px auto 0 auto;
}
.breadcrumb {
margin-top: -20px;
display: inline-block;
vertical-align: top;
}
/*
.breadcrumb:checked ~ .smart-nav-panels ul {
display: none;
}
#bread-home:checked ~ .smart-nav-panels > ul {
display: block;
}
*/
/* hide all uls except the 'home' ul by default, replaces both of the above */
.smart-nav-panels ul ul {
display: none;
}
/*
#bread-women:checked ~ .smart-nav-panels {
#home, #women {
display: block;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#home, #women, #womens-clothing {
display: block;
}
}
*/
/* these next 3 style definitions are very similar to what you had before (commented
above), except that there is no longer a need to unhide the 'home' ul, and we're
being more explicit about which uls to hide in correspondence with the state of the
breadcrumb nav */
#bread-home:checked ~ .smart-nav-panels {
#women {
display: none;
}
}
#bread-women:checked ~ .smart-nav-panels {
#women {
display: block;
}
#womens-clothing, #womens-shoes {
display: none;
}
}
#bread-womens-clothing:checked ~ .smart-nav-panels {
#women, #womens-clothing {
display: block;
}
}
/*
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child {
display: block;
}
*/
/* (i) the above didn't work because the ul isn't a direct descendant of the input,
rather it is a sibling, and in addition it doesn't matter which breadcrumb item is
checked now */
.smart-nav-panels li input:checked ~ ul {
display: block;
}
.smart-nav-panels {
margin: 0;
padding: 0;
ul {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background: lightgrey;
}
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
> ul:first-child {
ul {
left: 100%;
}
}
/* removed unnecessary styles here */
}
/* removed unnecessary style here */
This has solved some of the problems, but there are still many more. Solving some of them will, I suspect, create new ones. One immediate one I can think of is that you'll want to tie the state of the tiered menu to the breadcrumb in such a way that you only see as much of the breadcrumb as you're supposed to (right now you always see all of it).
At some point you're going to want events (for behaviour) and components will need to know about each other's state. While CSS has some state capabilities it provides nothing on the event front. These limitations, the cascading nature (discussed in depth in other questions, eg: lack of ancestor selector) and coupling to the HTML structure all contribute to make this a very hard problem to solve with HTML & CSS alone.
I understand the desire to have this type of navigation without JS and certainly this is an interesting problem to try and solve, but ultimately I think it's the wrong way to go about it.
There is a reason why javascript is so ubiquitous - our experience of the web as it is today simply wouldn't be the same without it.
(Thanks to Jess and other colleagues for the discussion that informed parts of this answer. I paraphrased liberally. Hopefully this is of benefit to someone else.)
Is it possible to create a conditional div display depending on another div's content being present or not? I'm looking for a CSS only solution.
I've used something like this before:
.myClass:empty:before {
content: 'content added to empty div';
}
to add content to an empty div. But since there is no way to create hyperlinks in the created pseudo-content, I'm looking for another way.
So let's assume my div structure is as follows:
<div class="div1"></div>
<div class="div2">This should be displayed</div>
Is it possible to do a css trick to display div2 if div1 is empty; but hide it if div1 has content?
Feel free to restructure the div hierarchy, what I'm looking for does not depend on the current div structure.
Looking for ideas. Thank you.
I'd suggest:
/* hiding the div.div2 element (and its content)
if it's the next element-sibling of div.div1: */
div.div1 + div.div2 {
display: none;
}
/* selecting the div.div2 element which is the next
element-sibling of an empty (div.div1:empty)
div.div1 element: */
div.div1:empty + div.div2 {
display: block;
}
/* hiding the div.div2 element (and its content)
if it's the next element-sibling of div.div1: */
div.div1 + div.div2 {
display: none;
}
/* selecting the div.div2 element which is the next
element-sibling of an empty (div.div1:empty)
div.div1 element: */
div.div1:empty + div.div2 {
display: block;
}
div.div1 {
border: 1px solid #f00;
color: #f00;
}
div.div2 {
color: #0f0;
border: 1px solid #0f0;
margin-bottom: 1em;
}
<div class="div1"></div>
<div class="div2">This should be displayed</div>
<div class="div1">This is 'div.div1' (it has content)</div>
<div class="div2">This should not be displayed</div>
use css- next element selecor
.div1:empty + div{
content: 'content added to empty div';
}
Thank you for the quick answers. Based on Alexis Peters' answer, I've created this one which worked like a charm. Putting it down for future reference:
div2 {
display: none;
}
.div1:empty + .div2{
display: block;
}
An explanation is (for explorers like me) CSS above says "set div2 to not display. If any .div2 follows an empty .div1 then set display to block".
Cheers.
Say you specify some div with height 500px. In this div, you have a list - maybe ol or ul - and instead of filling it up left-right, top-bottom (this can be done with display:inline-block on the li element), you want to fill it up right to left, bottom to top.
I think right to left can be done with something like float:right in the li element, but I wonder about going bottom to top?
Example result (elem1 is filled before elem2, etc.):
-----------------------------------
[elem10][elem9][elem8][elem7][elem6]
[elem5][elem4][elem3][elem2][elem1]
-----------------------------------
(So it's kind of like putting blocks on top of each other and sliding to the right.)
I hope I'm overthinking and there's actually an easy way to do this.
Thoughts appreciated.
PS. I've seen ol's new 'reversed' attribute in HTML5 and even if that helps I would prefer avoiding something that has very little browser support right now.
Only supported by WebKit, but -webkit-writing-mode: horizontal-bt; seems to work:
http://jsfiddle.net/zzXhp/
There may be other prefixed properties for it. Obviously it's not very well supported though.
Just rotate the list and then counter-rotate the li's
the HTML is
<ul class="container">
<li class="inner">one</li>
....
</ul>
the CSS is
.container {
left: 46px;
top: 100px;
width: 400px;
height: 400px;
position: absolute;
border: 1px solid black;
background-color: lemonchiffon;
}
.inner {
background-color: lightsalmon;
font-size: 20px;
margin: 20px;
width: 80px;
float: left;
}
.container:hover,
.container:hover li {
-webkit-transform: rotate(180deg);
-webkit-transition: all 3s;
}
In the DEMO I have done the effect in the hover, just to make it prettier. the real code would be without transitions :-)
To show something from right to left (usually pages in Arabic), you should use the dir tag.
dir="rtl" : RIGHT to LEFT
<ul id="myList" dir="rtl">
<li>1st</li>
<li>2nd</li>
<li>3rd</li>
</ul>
Here's a JSFIDDLE
A Simple JavaScript to do the whole work, no rtl required.
var list = document.getElementById("myList");
var i = list.childNodes.length;
while (i--)
list.appendChild(list.childNodes[i]);
Here's a JSFIDDLE
I made a shorter, unformatted version of #vals answer, credit goes to him.
The HTML:
<ul class="reverse">
<li>one</li>
...
</ul>
The CSS:
.reverse {
position: absolute;
list-style: none;
}
.reverse li {
margin: 5px;
float: left;
}
.reverse,
.reverse li {
-webkit-transform: rotate(180deg);
}
JSFIDDLE
Here's a solution for filling up from bottom to top and aligned right:
#mylist {
position:absolute;
top:58px;
right:4%;
height:40px;// height of max rows you might need - this allows two rows for me
line-height:1;
font-size:14px;
margin:0;
border: 1px dashed #38e800;
}
#mylist ul {
position:absolute;
bottom:0;
right:0;
overflow: hidden;
vertical-align:bottom;
list-style: none;
text-align:right;
margin:0 0 2px 0;
}
#mylist li {
display:inline-block;
padding:0 0 0 18px;
}
Use the below CSS for reversing from bottom to up:
ul {
display: flex;
flex-direction: column-reverse;
}
or use the below CSS for reversing from right to left:
ul {
display: flex;
flex-direction: row-reverse;
}
As a part of learning CSS (& practically applying it — by creating simple themes), today I wanted to know some proper ways of clearing floats in CSS.
I wanted to see how Twitter does it, so I downloaded Bootstrap, went through the bootstrap.css file, and found what I was looking for (I found two code blocks):
.clearfix {
*zoom: 1;
}
.clearfix:before, .clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
&
.container {
margin-left: auto;
margin-right: auto;
*zoom: 1;
}
.container:before, .container:after {
display: table;
content: "";
}
.container:after {
clear: both;
}
I immediately tried it out, and that specific part of my code looked like so:
<p class="sample-preview">
<span class="sample-preview">PREVIEW</span>
<em>This is italicized aka emphasized</em>, and so is <em>this</em>.<br />
<strong>This is bold aka strong emphasis</strong>, and so is <strong>this</strong>.<br />
Use <strong><em>italics and bold together</em></strong> if you <strong><em>have to</em></strong>.
</p>
+
p.sample-preview {
border: 1px solid #FFCCC9;
background: #FFEBE9;
outline: 2px solid #FFEBE9;
padding: 10px;
}
span.sample-preview {
display: inline-block;
float: right;
margin:0;
font-weight: bold;
font-size: 12px;
background: #FFCCC9;
padding: 2px 5px;
}
.sample-preview {
margin-left: auto;
margin-right: auto;
*zoom: 1;
}
.sample-preview:before, .sample-preview:after {
display: table;
content: "";
}
.sample-preview:after {
clear: both;
}
Although I am not entirely sure, I think this code is causing a weird bug on the page I tried it. Why do I think so? Everything seemed fine when I removed display: table; from the code using Firebug.
You can take a look at the page here and the bug is — the first pink box is taller than the content. What am I doing wrong?
The issue is that you're also clearing the floated menu to the right.
There's two solutions for that:
the usual is to float your content area itself to the left. This means that everything inside it is in a different float context. Your clear will only affect the elements inside of it.
another trick that works is specifying overflow: hidden on your sample-preview paragraph. This is probably easier to do. Specifying the overflow property on an element (but not set to visible) causes it to behave like a float container.
Cfr: http://www.brunildo.org/test/clear.html, http://webdesignerwall.com/tutorials/css-clearing-floats-with-overflow
I should also note that with this overflow trick, you don't need the clearfix at all.