Create three lines following element using pseudo class/elements - html

I'm trying to get a heading element on my page to look like:
I saw the steps shown at CSS: :before and :after pseudo elements in practice (see heading 'Styling titles') which displays a single line before and after the heading element. I liked that idea and wanted to expand it out to display three lines as per the sample image. Unlike image I was hoping for the lines to be thinner and not take up the full height space available but that's all I could mock up with limited tools/skills.
My issue is not getting three lines, but rather aligning each of those lines to their intended place. Currently they mess up and stack in an unexpected way (at least unexpected from my understanding).
Here is a JsFiddle showing my progress so far. I've created the h1 for text and two spans either side of the text but within the h1. My reasoning for this was to remove the single line from the h1 and apply the three lines via each span utilising pseudo-elements :after and :before for two of them.
Not sure where I have gone wrong or if it is even possible. I have complete access to HTML and CSS so the structure and styles are not locked down.
Let me know if I haven't been clear.

You can do it using two spans.
.long {
position: relative;
width: 100%;
}
.long:after, .long:before {
content: '';
position: absolute;
height: 3px;
width: 30px;
background: black;
top: 50%;
left: -34px;
}
.long:before {
left: calc(100% + 4px);
}
.title {
position: relative;
font-size: 50px;
margin-left: 40px;
}
.title:after, .title:before {
content: '';
position: absolute;
height: 20%;
width: 20px;
border-top: 3px solid black;
border-bottom: 3px solid black;
top: calc(100% - 31.2%*2);
right: -24px;
}
.title:before {
right: calc(100% + 4px)
}
<span class="title"><span class="long">text</span></span>
Also, possible with svg if you want round corners.
<svg width="170" height="50" viewBox="-10 0 170 50">
<defs>
<line id="small" x1="3" y1="3" x2="20" y2="3" stroke="black" stroke-width="3" stroke-linecap="round" />
<line id="large" x1="3" y1="3" x2="30" y2="3" stroke="black" stroke-width="3" stroke-linecap="round" />
</defs>
<text x="75" y="35" text-anchor="middle" font-size="50">text</text>
<use transform="translate(5,10)" xlink:href="#small" />
<use transform="translate(-5,17)" xlink:href="#large" />
<use transform="translate(5,24)" xlink:href="#small" />
<use transform="translate(125,10)" xlink:href="#small" />
<use transform="translate(125,17)" xlink:href="#large" />
<use transform="translate(125,24)" xlink:href="#small" />
</svg>

You could use a CSS background image, or gradient to achieve the same effect.
The CSS background will be something along the lines of:
background:linear-gradient(to bottom, #fff 0%, #fff 20%, transparent 20%, transparent 40%, #fff 40%, #fff 60%, transparent 60%, transparent 80%, #fff 80%, #fff 100%);

Why not create a left and right image and display it with the :before and :after like you are but instead of setting content: add background: url('img_left.png');?
Here is a Fiddle to show what I mean.

Related

How to use gradient in border in CSS3?

I want the above result, cant use the image because the height of the div is not fixed.
Any help will be appriciated.
You can use pseudo classes & gredient background to creating this. check updated snippet below ...
.msgBox {
padding: 3px;
background: #f9db31;
background: -webkit-linear-gradient(#f9db31 0%, #ff0000 100%);
background: -moz-linear-gradient(#f9db31 0%, #ff0000 100%);
background: -o-linear-gradient(#f9db31 0%, #ff0000 100%);
background: linear-gradient(#f9db31 0%, #ff0000 100%);
float: left;
margin: 50px;
position: relative;
border-radius: 5px;
}
.msgBox::before {
border-bottom: 30px solid transparent;
border-right: 30px solid #f9db31;
border-top: 0 solid transparent;
content: "";
height: 0;
left: -27px;
position: absolute;
top: 25px;
width: 0;
z-index: 999;
}
.msgBox::after {
border-bottom: 28px solid transparent;
border-right: 28px solid #fff;
border-top: 0 solid transparent;
content: "";
height: 0;
left: -21px;
position: absolute;
top: 27px;
width: 0;
z-index: 999;
}
.innerBox {
width: 400px;
min-height: 200px;
background: #fff;
border-radius: 5px;
}
<div class="msgBox">
<div class="innerBox">
</div>
</div>
SVG can be used to create such shapes. It offers simplicity and scale-ability.
However in case your case as you need flexible height element, may
be it doesn't fit your needs. I'm leaving my answer here for a possible alternate for some similar situations where it might be handy.
We can use SVG's path element to create a shape like above and stroke / fill it with some solid color, gradient or a pattern.
Only one attribute d is used to define shapes in path element. This attribute itself contains a number of short commands and few parameters that are necessary for those commands to work.
Following code will create the above shape:
<path d="M0,25 L25,30 V20
Q25,5 40,5 L460,5
Q475,5 475,20 L475,170
Q475,185 460,185 L40,185
Q25,185 25,170 L25,50 Z" />
Below is a brief description of path commands used in above code:
M command is used to define the starting point. It appears at the beginning and specify the point from where drawing should start.
L and V commands are used to draw straight lines.
Q command is used to draw curves.
Z command is used to close current path. It draws a straight line from current point to the starting point to close the shape.
Output Image:
Working Example:
body {
padding: 10px;
}
<svg width="500" height="200" viewBox="0 0 500 200">
<defs>
<linearGradient id="grad" x2="0" y2="1">
<stop offset="0" stop-color="yellow" />
<stop offset="0.5" stop-color="orange" />
<stop offset="1" stop-color="red" />
</linearGradient>
</defs>
<path d="M0,25 L25,30 V20
Q25,5 40,5 L460,5
Q475,5 475,20 L475,170
Q475,185 460,185 L40,185
Q25,185 25,170 L25,50 Z" stroke="url(#grad)" stroke-width="2" fill="none" />
</svg>
Useful Resources:
Below are some useful links for SVG:
Specification
MDN

Make border clip other elements and show background content

I'm trying to create a spinner where two dots intersect and the foremost one should clip the other letting the background be visible on few pixels of intersection.
It would be okay to use SVG if CSS isn't capable of this, but at the moment I can't find a way to achieve the effect in neither of the technologies.
I tried with clip-path but it doesn't seem to do what am I trying to do.
Ideas?
body {
background-image: linear-gradient(to right, yellow 0%, purple 100%);
}
.a, .b {
width: 50px;
height: 50px;
border-radius: 100%;
position: absolute;
top: 5em;
left: 50vw;
border: 4px solid white;
}
.a {
background: red;
}
.b {
background-color: blue;
margin-left: 30px;
}
<div class="a"></div>
<div class="b"></div>
It's easy to do in SVG. However you'll want to use a <mask> rather than a <clipPath>.
body {
background-image: linear-gradient(to right, yellow 0%, purple 100%);
}
svg {
margin: 5em 0 0 50vw;
}
<svg width="80" height="50">
<defs>
<mask id="clipred">
<rect width="100%" height="100%" fill="white"/>
<circle cx="55" cy="25" r="29" fill="black"/>
</mask>
</defs>
<circle cx="25" cy="25" r="25" fill="red" mask="url(#clipred)"/>
<circle cx="55" cy="25" r="25" fill="blue"/>
</svg>

Positioning overlapping SVGs inside a block element

I have a couple of circle SVGs that I am stacking on top of one another. In order to do that I have assigned them an absolute position style. My problem is I can't seem how to get the stacked SVGS to display within a block element, such as a DIV tag, when I do so.
This is what I have so far:
.card {
background-color:white;
border: 1px solid gray;
border-top: 10px solid gray;
padding:20px;
box-shadow: 1px 1px 1px #888888;
margin-bottom: 30px;
}
circle {
fill: transparent;
stroke-width: 30;
}
svg {
width: 150px;
height: 150px;
position: absolute;
}
<P>I would like to have the three pie charts stack on top of them like they are doing, but I would like for them to be inside the card (DIV).</P>
<DIV class="PieChart" style="stroke-dasharray: 377 377; stroke: #80F162;">
<svg>
<circle r="60" cx="50%" cy="50%"/>
</svg>
</DIV>
<DIV class="PieChart" style="stroke-dasharray: 255 377; stroke: #F06161;">
<svg>
<circle r="60" cx="50%" cy="50%"/>
</svg>
</DIV>
<DIV class="PieChart" style="stroke-dasharray: 189 377; stroke: #F4F464;">
<svg>
<circle r="60" cx="50%" cy="50%"/>
</svg>
</DIV>
An example of what I have so far can be found here:
https://jsfiddle.net/e82agLn2/
Any help would be greatly appreciated.
Thanks!
The reason this is happening is that you have 3 svg nodes that you're overlapping using position:absolute (and absolute positioning takes svg elements out of the wrapping div's flow);
You could use one svg tag( without position:absolute ) and use g tags to group the elements_
fiddle

Using CSS3 turn triangle into square with animation on hover

I am trying to develop a CSS box hover effect using HTML5 & CSS3 but I cannot get this to work. I would like to make an effect like seen below:
when the user is not hovering
when user is hovering
i.e. how can I make a blue triangle and turn it into a blue square when the user hovers over it using HTML5 and CSS3? I need this only using HTML5 & CSS3 and not using canvas.
This element work with canvas perfectly like as below
var ctx = document.getElementById("c").getContext("2d");
ctx.fillStyle = "#0000ff";
function normal() {
ctx.clearRect(0,0,256,256);
ctx.beginPath();
ctx.moveTo(256,256);
ctx.lineTo(256,0);
ctx.lineTo(0,0);
ctx.closePath();
ctx.fill(); bars()
ctx.fillStyle="#0000ff"; for (i=0;i
But I need only using HTML5 & CSS3 scripting languages
Using SVG: (the entire effect that you are looking for)
I know you've asked for HTML(5) + CSS(3) but you could also use a SVG path element to produce this effect like in the below snippet. (Note: This uses SVG animations and its browser support can be different compared to CSS animations.)
svg {
height: 150px;
width: 150px;
stroke: black;
}
#blue {
stroke: blue;
stroke-width: 10;
}
svg polygon {
fill: blue;
}
#white {
stroke: white;
stroke-width: 10;
}
#icon {
fill: transparent;
}
<svg viewBox='0 0 100 100'>
<defs>
<clipPath id='clipper' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,0z'>
<animate attributeType="XML" attributeName="d" from="M0,0 1,0 1,1 0,0z" to="M0,0 1,0 1,1 0,1z" dur="1s" begin="icon.mouseover" fill="freeze" />
<animate attributeType="XML" attributeName="d" from="M0,0 1,0 1,1 0,1z" to="M0,0 1,0 1,1 0,0z" dur="1s" begin="icon.mouseout" fill="freeze" />
</path>
</clipPath>
<g id='lines'>
<line x1='20' y1='30' x2='80' y2='30' />
<line x1='20' y1='50' x2='80' y2='50' />
<line x1='20' y1='70' x2='80' y2='70' />
</g>
</defs>
<use xlink:href='#lines' id='blue' />
<g clip-path='url(#clipper)'>
<polygon points='0,0 0,100 100,100 100,0' />
<use xlink:href='#lines' id='white' />
</g>
<g>
<polygon points='0,0 0,100 100,100 100,0' id='icon' />
</g>
</svg>
The below are answers to the question - how to turn triangle into square with animation.
Using Borders:
You could do it using border like in the below snippet. Initially only the right and top borders have the blue color but on hover we set the color to all border sides. This method is pretty simple and will work in all browsers (including IE8) but you cannot add content directly to this div (as doing so will affect the triangle shape) and so you'd have to place content on top of the shape using positioning or set the shape using a pseudo-element.
.shape{
height: 0px;
width: 0px;
border: 50px solid transparent;
border-color: blue blue transparent transparent;
transition: all 1s;
}
.shape:hover{
border-color: blue;
}
<div class='shape'></div>
Using Transforms:
You could add rotate transform on a pseudo-element, set overflow: hidden on parent to produce the triangle and then reverse/nullify the transform on hover.
.shape {
position: relative;
height: 100px;
width: 100px;
overflow: hidden;
}
.shape:after {
position: absolute;
content: '';
height: calc(100% * 1.414); /* using Pythogras theorem */
width: calc(100% * 1.414); /* using Pythogras theorem */
transform: rotate(-45deg);
transform-origin: left top;
background: blue;
transition: all 1s;
}
.shape:hover:after {
transform: rotate(0deg);
}
<div class='shape'></div>
You could also use a skewX transform instead of a rotate transform if you wish to avoid calculating the height and width like in the previous snippet.
.shape {
position: relative;
height: 100px;
width: 100px;
overflow: hidden;
}
.shape:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
transform: skewX(45deg);
transform-origin: left top;
background: blue;
transition: all 1s;
}
.shape:hover:after {
transform: skewX(0deg);
}
<div class='shape'></div>
Using Gradients:
You could use linear-gradients to create a triangle and then turn it into a square on hover by doubling the background-size.
.shape{
height: 100px;
width: 100px;
background: linear-gradient(to bottom left, blue 49.5%, transparent 50.5%);
background-position: 100% 0%;
background-size: 100% 100%;
transition: all 1s;
}
.shape:hover{
background-size: 200% 200%; /* just double the background size on hover */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='shape'></div>
In spite of the complete answer from Harry, couldn't resist to post an answer with another approach, suggested by the image in the OP.
Let's use blend modes, and see what can be achieved (but with more limited support)
.test {
width: 200px;
height: 200px;
background-color: white;
display: inline-block;
background-image: linear-gradient(blue, blue), linear-gradient(blue, blue), linear-gradient(blue, blue);
background-size: 100px 30px;
background-repeaT: no-repeat;
background-position: center 30px, center center, center 140px;
border: solid 1px black;
position: relative;
overflow: hidden;
}
.test:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background: linear-gradient(45deg, yellow 50%, transparent 50%);
mix-blend-mode: difference;
transition: all 1s;
}
.one:after {
transform-origin: bottom right;
}
.one:hover:after {
transform: rotate(-45deg);
}
.two:hover:after {
opacity: 0;
}
.three:after {
background: none;
box-shadow: -1000px 1000px 0px 1000px yellow;
transform-origin: top left;
transform: rotate3d(1,1,0,87deg);
}
.three:hover:after {
transform: rotate3d(1,1,0,0deg);
}
<div class="test one"></div>
<div class="test two"></div>
<div class="test three"></div>
the third one is a little bit tricky, and not quite perfect. But you get the idea.

Creating a skewed triangle shape

Is it possible to create the shape produced by this Fiddle. But then with no JavaScript but CSS3 (with <div>) ?
Basically this:
for(var i = 0; i < coords.length; i += 1) {
if(coords[(i + 1)] != undefined) {
ctx.beginPath();
ctx.moveTo(coords[i].x, coords[i].y);
ctx.lineTo(coords[(i + 1)].x, coords[(i + 1)].y);
ctx.stroke();
} else {
ctx.beginPath();
ctx.moveTo(coords[i].x, coords[i].y);
ctx.lineTo(coords[0].x, coords[0].y);
ctx.stroke();
}
}
So you have points that needs to connect to each other?
Use svg, if you don't want to use canvas.
<svg width="100" height="100">
<path d="M0 0 l100 10 l-40 90z" fill="none" stroke="black" stroke-width="2" />
</svg>
Path command for 8,8,10,10,30,30,49,10 would be M8 8 L10 10 L30 40 L49 10z.
<svg width="49" height="40" viewBox="0 0 50 41">
<path d="M8 8 L10 10 L30 40 L49 10z" fill="none" stroke="black" stroke-width="2" />
</svg>
To apply a click event to the shape, you could use pointer-events: all on #test.
#test {
pointer-events: all;
}
<svg width="49" height="40" viewBox="0 0 50 41">
<path id="test" d="M8 8 L10 10 L30 40 L49 10z" fill="none" onclick="alert('Works')" stroke="black" stroke-width="2" />
</svg>
Note: Posting this answer just because you asked with CSS3, but the complexity and possible calculation overhead involved in this approach is proof enough why CSS shouldn't be used for this. Please do not use this approach.
A bit of explanation on how this was achieved:
A div is created with top and right border (1px black) and the other two borders are set to none.
This div is then skewed a bit to make it appear as though the edge on the right side is a bit slanted.
Inside the shape, a pseudo-element with only a right border is created and it is also skewed to produce the diagonal line from the right-bottom to the left-top. Transform origin is set as right-bottom to avoid positioning overhead.
An anchor tag is added within the parent div and the overflow is set to hidden so that only the portion within the shape is clickable.
The user select on the anchor tag are disabled to prevent a double click from selecting a blank space within the div.
Finally the whole container div is rotated a bit to make it look as though the triangle is not parallel to x-axis.
document.getElementById("clickme").onclick = function() {
alert('Hi! I work alright.');
}
div {
position: relative;
height: 50px;
width: 45px;
border: 1px solid black;
border-left: none;
border-bottom: none;
-webkit-transform: skew(-10deg) rotate(5deg);
-moz-transform: skew(-10deg) rotate(5deg);
transform: skew(-10deg) rotate(5deg);
overflow: hidden;
}
a {
display: block;
content: '';
margin-left: 0px;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
height: 100%;
width: 100%;
}
div:after {
position: absolute;
top: 0px;
left: 0px;
content: '';
height: 50px;
width: 45px;
-webkit-transform: skew(42deg);
-webkit-transform-origin: left bottom;
-moz-transform: skew(42deg);
-moz-transform-origin: left bottom;
transform: skew(42deg);
transform-origin: left bottom;
border-right: 1px solid black;
}
<div>
</div>
Another option to create a skewed triangle shape would be to use clip-path like in below snippet. The shape is created by applying the same clip-path on the main container element and a pseudo-element which is smaller than the container.
document.getElementById("clickme").onclick = function() {
alert('Hi! I work alright.');
}
div {
position: relative;
height: 150px;
width: 150px;
background: black;
-webkit-clip-path: polygon(0% 0%, 100% 20%, 70% 100%);
}
div:after{
position: absolute;
content: '';
height: calc(100% - 5px);
width: calc(100% - 5px);
top: 2px;
left: 3px;
background: white;
-webkit-clip-path: polygon(0% 0%, 100% 20%, 70% 100%);
}
/* Just for demo */
div{
transition: all 1s;
}
div:hover{
height: 250px;
width: 250px;
}
<div id="clickme"></div>
You can do it by embeding SVG as CSS. Quote from:
http://css-tricks.com/using-svg/
"Another way to use SVG's is to convert them into Data URI's. Data URI's might not save you actual file size, but can be more efficient because the data is right there. It doesn't require an additional HTTPRequest.
Mobilefish.com has an online conversion tool for that (http://www.mobilefish.com/services/base64/base64.php). Simply paste in the contents of your SVG file and fill out the form and it will display the results in a textarea for you to copy. Remember to remove line breaks in the data it gives you back.
...
You can use that anywhere we've talked about so far (except inline because that just doesn't make sense) Just put the gibberish where it says [data] in these examples.
As CSS
.logo {
background: url(data:image/svg+xml;base64,[data]);
}
"