Tree diagram - Move last child's to one level in html/css - html

I want to create a tree diagram with last child's of the nodes should be in nth(last row of the tree) level. I am taking reference from here. As of now i am getting output like this(left), trying to get as right image.
I have tried with height and margin top in :before and :after, The links between the nodes are not coming correct. I am iterating the data for tree dynamically, there may be more levels if have more tree data. so need to set the line connection between node as generic. How can i get this? Suggestions please.
* {
margin: 0 auto;
padding: 0;
text-align: center;
color: black;
font-family: tahoma;
}
.items ul {
padding-top: 20px;
position: relative;
}
/* Make all children "inline" */
.items li {
/*float: left;*/
display: inline-block;
text-align: center;
list-style-type: none;
position: relative;
padding: 20px 5px 0 5px;
}
/* Add horizontal connector. Note: they are 2 pseudo-elements */
.items li::before, .items li::after {
content: '';
position: absolute;
top: 0;
right: 50%;
width: 55%;
height: 42px;
z-index: -1;
border-top: 1px solid #CCC;
}
.items li::after {
border-left: 1px solid #CCC;
left: 50%;
right: auto;
}
/* Remove left and right connector from a single child */
.items li:only-child::after, .items li:only-child::before {
display: none;
}
.items li:only-child {
padding-top: 0;
}
/* Remove "outer" connector */
.items li:first-child::before, .items li:last-child::after {
border: 0 none;
}
/* Add back the down connector for last node */
.items li:last-child::before {
border-right: 1px solid #CCC;
border-radius: 0 5px 0 0;
}
/* Add curve line to the first child's connector */
.items li:first-child::after {
border-radius: 5px 0 0 0;
}
/* Add down connector from parent */
.items ul ul::before {
content: '';
border-left: 1px solid #CCC;
z-index: -1;
height: 20px;
position: absolute;
top: 0px;
left: 50%;
width: 0;
}
/* Add cosmetic for each item */
.items li a {
font-size: 12px;
background-color: white;
border: 1px solid #CCC;
padding: 5px 10px;
height: 14px;
text-decoration: none;
display: inline-block;
border-radius: 4px;
}
/* Change bg-color while hovering each item */
.items li a:hover {
background-color: #EEF;
}
/* EXPERIMENTAL for multiple parents */
/* Add margin for the parents */
.items li a:not(:only-of-type) {
position: relative;
margin-bottom: 16px;
}
/* Add "down" connector (vertical line) from each multi-parent, EXCEPT the last one */
.items li > a:not(:last-of-type)::after{
content: '';
position: absolute;
border-left: 1px solid #CCC;
border-bottom: 1px solid #CCC;
top: 20px;
width: 75%;
height: 20px;
left: 50%;
z-index: -1;
}
/* Special case for the last multiple-parent, using border-right */
.items li > a:not(:only-of-type):last-of-type::after {
content: '';
position: absolute;
border-right: 1px solid #CCC;
border-bottom: 1px solid #CCC;
top: 20px;
width: 50%;
height: 20px;
right: 50%;
z-index: -1;
border-bottom-right-radius: 5px;
}
/* Give the curve line to the first multiple parent .... */
.items li > a:not(:only-of-type):first-child::after {
border-bottom-left-radius: 5px;
}
/* The middle element of multi-parents*/
.items li > a:not(:first-child):not(:last-of-type)::before {
content: '';
position: absolute;
border-bottom: 1px solid #CCC;
top: 40px;
width: 50%;
right: 50%;
z-index: -1;
}
.items ul:last-of-type li {
padding-left: 0;
padding-right: 0;
}
<div class="items">
<ul>
<li>
Dagon
Veil of Discord
Other Parent Item
<ul>
<li>
Null Talisman
<ul>
<li>Circlet</li>
<li>Mantle of Intelligence
<ul>
<li>earth
<ul>
<li>marsh</li>
<li>Mantle of agiled</li>
</ul>
</li>
<li>quick sun</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

Related

CSS technique for a horizontal line with words in the middle plus vertical borders

I'm trying to move the entire border "up" so the bottom border lines up with the middle of the text. Very similar to this question, but I want to keep the left and right borders (they must be pushed up too). The reason for this is the text relates to the information above it.
https://jsfiddle.net/8c039kzy/
My jsfiddle is close but the left / right borders don't go high enough. So I want something like this:
|--------Info above is Important!--------|
(But the bottom of the left / right borders don't leak down past the horizontal border)
Use a :before pseudo element to draw the horizontal line instead.
h5 {
width: 100%;
text-align: center;
border-left: 1px solid #000;
border-right: 1px solid #000;
margin: 10px 0 20px;
position: relative;
}
h5:before, h5:after {
content: '';
position: absolute;
}
h5:before {
top: 50%;
background: #000;
height: 1px;
left: 0; right: 0;
}
h5:after {
background: #fff;
top: calc(50% + 1px);
bottom: 0;
left: -1px; right: -1px;
}
span {
background: #FFF;
padding: 0 10px;
position: relative;
z-index: 1;
}
<h5><span>Refer to Info above</span></h5>
I think you want this :
h5 {
position: relative;
text-align: center;
border-left: 1px solid #000;
border-right: 1px solid #000;
}
h5 span {
background: white;
padding: 0 15px;
position: relative;
z-index: 1;
}
h5:before {
background: black;
content: "";
display: block;
height: 1px;
position: absolute;
top: 50%;
width: 100%;
}
h5:before {
left: 0;
}
<h5><span>Refer to Info above</span></h5>
I created a sides line and I used just right and left borders, is this that you want?
h5 span:before, h5 span:after {
display:inline-block;
content: "";
vertical-align: bottom;
height: .5em;
border-top: 1px solid #000;
width: 200px;
}
<h5><span>Refer to Info above</span></h5>
other way to do this :) but with lines of given width

CSS ribbon "menu" isn't working as desired

So I've created part of a ribbon menu I plan on using myself. So here is what it looks like so far:
Before hover:
On hover:
Basically, I want it to show my social icon as well as being able to use my other banners when i add them in.
Here is the code that I am using so far:
<body>
<ul class="social">
<li class="ribbon" media="facebook"><i class="fa fa-facebook" aria-hidden="true"></i></li>
</ul>
<script src="https://use.fontawesome.com/c2f336433a.js"></script>
</body>
Here is the CSS:
#import 'reset';
#import 'mixins';
ul.social {
position: absolute;
z-index: 4;
margin: -225px auto;
list-style: none;
right: 0;
li.ribbon {
float: right;
cursor: pointer;
position: relative;
width: 75px;
height: 250px;
border: none;
color: white;
padding: 5px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
#include transition(all .2s ease-in-out);
#include filter(drop-shadow(0 1px 10px rgba(0, 0, 0, 0.5)));
span {
line-height: 20px;
font-size: 5em;
}
}
li.ribbon:hover {
margin-top: 70px;
color: white;
}
li.ribbon:before {
content: '';
position: absolute;
top: 100%; left: 0;
width: 0; height: 0;
border-top: 25px solid blue;
border-right: 50px solid transparent;
}
li.ribbon:after {
content: '';
position: absolute;
top: 100%; right: 0;
width: 0; height: 0;
border-top: 25px solid blue;
border-left: 50px solid transparent;
}
li.ribbon[media="facebook"] {
background: #3b5998;
color: #1e2e4f;
margin-right: 5px;
}
li.ribbon[media="facebook"]:before,
li.ribbon[media="facebook"]:after {
border-top-color: #3b5998;
}
}
Note that the reset is just an eric meyer reset and the mixins are just for transitions etc...
The reason why you weren't able to see the icon was because there was a negative margin of 225px on the ul. On hover, only the margin-top of the li was being set to 70px but the ul still has the negative margin, so the li is still around 155px above the viewport. This means that the a which is not positioned (that is, has static positioning) and is near the top of the li is still not visible.
You can correct this by avoiding the margin on the ul and just moving the li around. I've used the transform: translateY() to move the li around because that is better for performance than using margins (which need repainting).
I have also added some extra properties like text-align, line-height etc for a better look.
ul.social {
position: absolute;
z-index: 4;
margin: 0px auto; /* modified */
list-style: none;
right: 0;
}
ul.social li.ribbon {
float: right;
cursor: pointer;
position: relative;
width: 75px;
height: 100px; /* modified */
border: none;
color: white;
padding: 5px;
text-align: center; /* added */
line-height: 100px; /* added, equal to height */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
transform: translateY(-100%); /* added */
transition: all .2s ease-in-out;
-webkit-filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.5));
}
ul.social li.ribbon span {
line-height: 20px;
font-size: 5em;
}
ul.social li.ribbon:hover {
transform: translateY(0%); /* added */
/* margin-top: 70px; removed for better performance */
}
ul.social li.ribbon:before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 0;
height: 0;
border-top: 25px solid blue;
border-right: 50px solid transparent;
}
ul.social li.ribbon:after {
content: '';
position: absolute;
top: 100%;
right: 0;
width: 0;
height: 0;
border-top: 25px solid blue;
border-left: 50px solid transparent;
}
ul.social li.ribbon[media="facebook"] {
background: #3b5998;
color: #1e2e4f;
margin-right: 5px;
}
ul.social li.ribbon[media="facebook"]:before,
ul.social li.ribbon[media="facebook"]:after {
border-top-color: #3b5998;
}
/* added */
ul.social li.ribbon a {
color: white;
}
<body>
<ul class="social">
<li class="ribbon" media="facebook"><i class="fa fa-facebook" aria-hidden="true"></i>
</li>
</ul>
<script src="https://use.fontawesome.com/c2f336433a.js"></script>
</body>

Show text on top of the tick in the ruler

The code is provided in the fiddle link below.
JSFiddle Link
Code:
$(function() {
// Build "dynamic" rulers by adding items
$(".ruler[data-items]").each(function() {
var ruler = $(this).empty(),
len = Number(ruler.attr("data-items")) || 0,
item = $(document.createElement("li")),
i;
for (i = 0; i < len; i++) {
ruler.append(item.clone().text(i + 1));
}
});
// Change the spacing programatically
function changeRulerSpacing(spacing) {
$(".ruler").
css("padding-right", spacing).
find("li").
css("padding-left", spacing);
}
$("#spacing").change(function() {
changeRulerSpacing($(this).val());
});
});
.ruler, .ruler li {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
}
/* IE6-7 Fix */
.ruler, .ruler li {
*display: inline;
}
.ruler {
background: lightYellow;
box-shadow: 0 -1px 1em hsl(60, 60%, 84%) inset;
border-radius: 2px;
border: 1px solid #ccc;
color: #ccc;
margin: 0;
height: 3em;
padding-right: 1cm;
white-space: nowrap;
}
.ruler li {
padding-left: 1cm;
width: 2em;
margin: .64em -1em -.64em;
text-align: center;
position: relative;
text-shadow: 1px 1px hsl(60, 60%, 84%);
}
.ruler li:before {
content: '';
position: absolute;
border-left: 1px solid #ccc;
height: .64em;
top: -.64em;
right: 1em;
}
/* Make me pretty! */
body {
font: 12px Ubuntu, Arial, sans-serif;
margin: 20px;
}
div {
margin-top: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="ruler"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
<div>
<ul class="ruler" data-items="10"></ul>
</div>
<div>
<label for="spacing">Spacing</label>
<select id="spacing">
<option>1cm</option>
<option>2cm</option>
<option>1in</option>
<option>1em</option>
<option>20px</option>
</select>
</div>
How can I show the text on top, next to the li tick in the provided link?
Currently, I am adding vertical-align:top to the css .ruler li but nothing changes in the UI.
Please check the image below. The requirement is shown in blue.
What css property in what css class do I need to add to make sure the text is shown at top and next to the tick?
Simply move the list items slightly to the right and up. Then move the :before pseudo elements the same amount to the left and down.
http://jsfiddle.net/kwcug/1006/
And I'm not sure why my update causes JSFiddle to think this one now has 1006 revisions.
Add some left position to your ruler li and adjust your right position in li:before
$(function() {
// Build "dynamic" rulers by adding items
$(".ruler[data-items]").each(function() {
var ruler = $(this).empty(),
len = Number(ruler.attr("data-items")) || 0,
item = $(document.createElement("li")),
i;
for (i = 0; i < len; i++) {
ruler.append(item.clone().text(i + 1));
}
});
// Change the spacing programatically
function changeRulerSpacing(spacing) {
$(".ruler").
css("padding-right", spacing).
find("li").
css("padding-left", spacing);
}
$("#spacing").change(function() {
changeRulerSpacing($(this).val());
});
});
.ruler,
.ruler li {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
}
/* IE6-7 Fix */
.ruler,
.ruler li {
*display: inline;
}
.ruler {
background: lightYellow;
box-shadow: 0 -1px 1em hsl(60, 60%, 84%) inset;
border-radius: 2px;
border: 1px solid #ccc;
color: #ccc;
margin: 0;
height: 3em;
padding-right: 1cm;
white-space: nowrap;
}
.ruler li {
padding-left: 1cm;
width: 2em;
margin: .64em -1em -.64em;
text-align: center;
position: relative;
text-shadow: 1px 1px hsl(60, 60%, 84%);
top: -.64em;
left: .64em
}
.ruler li:before {
content: '';
position: absolute;
border-left: 1px solid #ccc;
height: .64em;
right: 1.4em;
}
/* Make me pretty! */
body {
font: 12px Ubuntu, Arial, sans-serif;
margin: 20px;
}
div {
margin-top: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" src="http://fonts.googleapis.com/css?family=Ubuntu" />
<ul class="ruler">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<div>
<ul class="ruler" data-items="10"></ul>
</div>
<div>
<label for="spacing">Spacing</label>
<select id="spacing">
<option>1cm</option>
<option>2cm</option>
<option>1in</option>
<option>1em</option>
<option>20px</option>
</select>
</div>
Does this help?
http://jsfiddle.net/kwcug/1008/
I changed this
.ruler li {
margin: .64em -1em -.64em;
}
.ruler li:before {
content: '';
position: absolute;
border-left: 1px solid #ccc;
height: .64em;
top: -.64em;
right: 1em;
}
to
.ruler li:before {
content: '';
border-left: 1px solid #ccc;
margin-right: .2em;
}
.ruler li {
margin: 0 -1em -.64em;
}

CSS overlapping border of parent element, negative margin

I have nested elements, the container has a border style of one sort and I want some of the elements inside it to have their own border overlapping the container's border. I tried using negative margin, but the border of the child is hidden underneath the parent's (seems to be overflow issue).
HTML:
<div class="right">
<div class="itemlist">
<ol>
<li>Abc</li>
<li class="special">Abc</li>
<li>Abc</li>
<li>Abc</li>
<li class="special">Abc</li>
<li>Abc</li>
<li>Abc</li>
</ol>
</div>
</div>
CSS:
.right {
position: fixed;
right: 0;
top: 0;
width: 200px;
height: 100%;
z-index: 100;
display: flex;
flex-direction: column;
border-left: 3px solid #76ff03;
}
.right .itemlist {
flex: 1;
overflow-y: auto;
}
.itemlist > ol > li {
border-bottom: 1px solid #76ff03;
padding-left: 20px;
}
.itemlist > ol > li:hover, .itemlist > ol > li.special {
border-left: 10px solid #2196f3;
border-bottom: 1px solid #2196f3;
margin-left: -3px;
}
I've seen some examples of this done and can make it work in some cases, but not consistently. I have an example JSFiddle with some layout, below is a picture of whet two of the list elements look like and what I want them to look like.
http://jsfiddle.net/jkondratowicz/e6uunLa4/1/
Here is a way to do it removing the margin on it's parent container and adding it to each row individually
.right {
position: fixed;
right: 0;
top: 0;
width: 200px;
background: #78909c;
height: 100%;
z-index: 100;
display: flex;
flex-direction: column;
}
.itemlist > ol > li {
border-bottom: 1px solid #76ff03;
border-left: 3px solid #76ff03;
padding-left: 20px;
}
Here are the styles you need using box-shadow
.itemlist > ol > li {
box-shadow: inset 3px -1px 0px 0px #76ff03;
padding-left: 20px;
}
.right .itemlist {
flex: 1;
overflow-y: auto;
box-shadow: inset 3px 0px 0px 0px #76ff03;
}
.itemlist > ol > li:hover, .itemlist > ol > li.special {
box-shadow: inset 10px -1px 0px 0px #2196f3;
padding-left: 25px;
}
.right {
position: fixed;
right: 0;
top: 0;
width: 200px;
background: #78909c;
height: 100%;
z-index: 100;
display: flex;
flex-direction: column;
}
http://jsfiddle.net/xnjn17uL/2/

Css border shape and working with hover state

Question: Why when you make css shapes using the border tricks seen here does it move the visual of your element out of its dom-box?
So I found these two questions while searching:
Can I use CSS hover on this complex irregular shaped link
Hovering on overlapping CSS3 shapes
But I don't think that either addresses my question (though if I want to change my html structure I could probably use the answer from that first link.
Example pics to illustrate:
Which means that when I hover over the bottom half of that element it highlights the one below it.
I understand that even though I have a diamond visually the box-model says that it's still a rectangle, but why is the diamond not contained inside that rectangle?
Is there a way around this - with css/markup -, or do I have to go with the maping solution from the first link?
My source code incase anyone wants that:
<header class="navigation">
<div class="nav">
<ul class='master_nav'>
<li>Home</li>
<li>About</li>
<li>Resources</li>
<li>FAQs</li>
</ul>
</div>
</header>
.navigation li{
height: 0;
width: 0;
margin: 10px 0;
list-style: none;
position: relative;
border: 70px solid transparent;
border-bottom: 90px solid #2B2B2B;
display: block;
}
.navigation li:after{
content: '';
position: absolute;
left: -70px; top: 90px;
width: 0;
height: 0;
border: 70px solid transparent;
border-top: 90px solid #2B2B2B;
}
.navigation li a{
height: 25px;
width: 100%;
display: inline-block;
text-decoration: none;
color: #b7b7b7;
position: absolute;
top: 75px;
left: -19px;
}
.navigation li:hover a{
color: #010101;
}
I'm not 100% sure why but you can get around it by making the <a> the hover target and filling the space:
.navigation li a{
height:70px;
width: 80px;
display: block;
text-decoration: none;
color: #b7b7b7;
position: absolute;
top: 38px;
left: -40px;
padding-top: 40px;
text-align: center;
border: 1px solid yellow; //just to see it.
}
.navigation a:hover{
color: #010101;
}
Here's a working pen http://codepen.io/willthemoor/pen/KpcLD/ (updated)
Edit
Getting it lined up perfectly might take a little trial and error but you can use the transform property to rotate and skew the <a> to match the shape. I updated the pen.
I had to add some skew to match the shape of the diamonds, and then use a a <span> inside of the <a> to sort revert the changes. Skew messes with text so you might try to find a happy medium between the shape of your border diamonds and the shape you can make without using skew.
.navigation li{
height: 0;
width: 0;
margin: 10px 0;
list-style: none;
position: relative;
border: 70px solid transparent;
border-bottom: 90px solid #2B2B2B;
display: block;
/* position fix */
top: -90px;
left: -19px;
}
.navigation li:before{
content: '';
position: absolute;
left: -70px;
top: 90px;
width: 0;
height: 0;
border: 70px solid transparent;
border-top: 90px solid #2B2B2B;
}
.navigation li a{
background-color: rgba(255, 0, 0, 0.3);
color: #B7B7B7;
display: block;
height: 68px;
left: -55px;
padding-top: 40px;
position: absolute;
text-align: center;
text-decoration: none;
top: 34px;
-webkit-transform:rotate(314deg);
transform: rotate(314deg);
width: 110px;
}
.skew li a {
/* following lines it up better but hard to 'rewind it' on the span witout the text looking a little strange */
-webkit-transform: rotate(310deg) skewX(-11deg) skewY(-2deg);
transform: rotate(310deg) skewX(-11deg) skewY(-2deg);
height: 73px;
left: -55px;
width: 112px;
}
.navigation a:hover{
background-color: rgba(0,0,255,.3);
color: #010101;
}
.navigation a > span {
display: block;
/* and reset the text*/
-webkit-transform: rotate(46deg);
transform: rotate(46deg);
}
.skew a > span {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
letter-spacing: .04em;
}
/*
lis are actually covering each other on the bottoms.
Adding this hacky bit makes the bottom of the diamond link work. Could use classes instead.
*/
.navigation li { z-index: 100; }
.navigation li + li { z-index: 90; }
.navigation li + li + li { z-index: 80; }
.navigation li + li + li + li { z-index: 70; }