Modify element :before CSS rules programmatically in React - javascript

I have an element whose :before style has to be modified based on calculations.
export class Content extends React.Component {
render() {
return (
<div className="ring-base">
<div className="ring-left" style={{/* Change here */}}></div>
<div className="ring-right" style={{/* Change here */}}></div>
<div className="ring-cover">
<div className="ring-text">10%</div>
</div>
</div>
);
}
}
CSS Code:
.ring-base {
position: absolute;
height: 200px;
width: 200px;
border-radius: 50%;
background: red;
transform: rotate(90deg);
overflow:hidden;
}
.ring-cover {
position: absolute;
height: 180px;
width: 180px;
background: #fff;
border-radius: 50%;
top: 5%;
left: 5%;
}
.ring-cover .ring-text {
position: absolute;
width: 100%;
height: 100%;
text-align: center;
font-size: 2em;
display: flex;
justify-content:center;
align-content:center;
flex-direction:column;
transform: rotate(-90deg);
}
.ring-right, .ring-left {
height: 100px;
width: 200px;
overflow: hidden;
position: absolute;
}
.ring-right:before, .ring-left:before {
height: inherit;
width: inherit;
position: absolute;
content: "";
border-radius: 100px 100px 0 0;
background-color: grey;
transform: rotate(0deg);
}
.ring-right {
-webkit-transform-origin: 50% 0%;
-moz-transform-origin: 50% 0%;
-ms-transform-origin: 50% 0%;
transform-origin: 50% 0%;
transform: rotateZ(0deg);
}
.ring-left {
transform: rotate(180deg);
-webkit-transform-origin: 50% 100%;
-moz-transform-origin: 50% 100%;
-ms-transform-origin: 50% 100%;
transform-origin: 50% 100%;
}
.ring-right:before {
-webkit-transform-origin: 50% 100%;
-moz-transform-origin: 50% 100%;
-ms-transform-origin: 50% 100%;
transform-origin: 50% 100%;
transform: rotate(0deg);
}
.ring-left:before {
-webkit-transform-origin: 50% 100%;
-moz-transform-origin: 50% 100%;
-ms-transform-origin: 50% 100%;
transform-origin: 50% 100%;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
The ask is to be able to update the transform property for .ring-left:before and .ring-right:before via ReactJS.
If there is a way to not update the :before class and change the CSS to not make use of :before at all, then do suggest that as well.
Js-Fiddle

You can iterate document.styleSheets, set .style of .cssRules where .selectorText matches pseudo selector
let sheets = document.styleSheets;
let selector = "div::before";
let replacementContent = '"after"';
for (let sheet of sheets) {
for (let rule of sheet.cssRules) {
if (rule.selectorText === selector) {
rule.style["content"] = replacementContent;
}
}
}
div:before {
content: "before";
color: red;
font-weight: bold;
text-align: center;
text-shadow: 2px 2px 2px #000;
background: green;
width: 50px;
height: 50px;
display: block;
}
<div></div>

Related

How can I make loader cover the all page

There are my codes below. I want the loader cover the all page but it just covers the top. How can I make it cover the all page? There are my codes below. I want loader cover the all page but it just covers the top. How can I make it cover the all page?
/*loader*/
.loader-wrapper {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #333233;
display:flex;
justify-content: center;
align-items: center;
}
.loader {
display: inline-block;
width: 30px;
height: 30px;
position: relative;
border: 4px solid #Fff;
animation: loader 3s infinite ease;
}
.loader-inner {
vertical-align: top;
display: inline-block;
width: 100%;
background-color: #fff;
animation: loader-inner 3s infinite ease-in;
}
#keyframes loader {
0% { transform: rotate(0deg);}
25% { transform: rotate(180deg);}
50% { transform: rotate(180deg);}
75% { transform: rotate(360deg);}
100% { transform: rotate(360deg);}
}
#keyframes loader-inner {
0% { height: 0%;}
25% { height: 0%;}
50% { height: 100%;}
75% { height: 100%;}
100% { height: 0%;}
}
<!--loader-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js" integrity="sha512-AFwxAkWdvxRd9qhYYp1qbeRZj6/iTNmJ2GFwcxsMOzwwTaRwz2a/2TX225Ebcj3whXte1WGQb38cXE5j7ZQw3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="loader-wrapper">
<span class="loader"><span class="loader-inner"></span></span>
</div>
<script>
$(window).on("load",function(){
$(".loader-wrapper").fadeOut("slow");
});
</script>
<!--loader-->
add position:fixed in main wrapper
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0

How can I reverse this animation smoothly on mouseout?

I have this flipcard I put together, and when you hover over it, it flips 180 degrees on it's x-axis, and then expands. When I mouse-off of the element, I would like for this element to flip back the opposite way smoothly, the way it came in. Instead of the sudden change back when you mouseout like it is right now.
Also, it should be noted that I would like the animation to use animation: forwards for as long as the mouse is hovering over the element. (ie. so long as the user is hovering over the element, it should remain flipped, and enlarged.)
Is there any way to do this using just CSS? Or will I need Javascript? If so, I'd like to do this with pure Vanilla JS.
I have been poking around for solutions on Stack Overflow, and can't seem to find a definitive answer, or am not typing in the correct question.
html, body {
background: #f2edea;
height: 100%;
width: 100%;
}
.container {
width: 250px;
height: 320px;
margin: auto;
position: relative;
top: 35%;
}
img {
width: 100%;
max-height: 100%;
}
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
}
#keyframes grow {
from {
transform: rotateY(0) scale(1);
}
to {
transform: rotateY(180deg) scale(2);
}
}
.flipcard:hover {
animation: grow 1s forwards;
}
.front-side {
height: 100%;
width: 100%;
position: relative;
backface-visibility: hidden;
}
.back-side {
width: 100%;
height: 100%;
transform: rotateY(180deg);
position: absolute;
top: 0;
border-radius: 3px;
}
<div class='container'>
<div class='flipcard'>
<div class='front-side'>
<img src='https://pre00.deviantart.net/4121/th/pre/i/2018/059/6/7/brigitte_by_raikoart-dc4kzas.png'>
</div>
<div class='back-side'>
<img src="https://img00.deviantart.net/e0ec/i/2017/297/8/c/mercy_by_raikoart-dbrm54b.png">
</div>
</div>
</div>
You'd better use transition between normal and hover states.
Note that you have to track hover on .container to avoid jumping and flickering.
html, body {
background: #f2edea;
height: 100%;
width: 100%;
}
.container {
width: 250px;
height: 320px;
margin: auto;
position: relative;
}
img {
width: 100%;
max-height: 100%;
}
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
transition: all .5s ease-in-out;
}
.container:hover .flipcard {
transform: rotateY(180deg) scale(2);
}
.front-side {
height: 100%;
width: 100%;
position: relative;
backface-visibility: hidden;
}
.back-side {
width: 100%;
height: 100%;
transform: rotateY(180deg);
position: absolute;
top: 0;
border-radius: 3px;
}
<div class='container'>
<div class='flipcard'>
<div class='front-side'>
<img src='https://pre00.deviantart.net/4121/th/pre/i/2018/059/6/7/brigitte_by_raikoart-dc4kzas.png'>
</div>
<div class='back-side'>
<img src="https://img00.deviantart.net/e0ec/i/2017/297/8/c/mercy_by_raikoart-dbrm54b.png">
</div>
</div>
</div>
The reason this happens is because on the default non-hover state there's no animation state to return to. You have two options for this.
Don't use animations and just transition the effect on hover.
This way on out the properties will return to their non-hover state with transition.
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
transform: rotateY(0) scale(1);
transition: all 0.3s ease;
}
.flipcard:hover {
transform: rotateY(180deg) scale(2);
}
https://jsfiddle.net/255mnwxr/5/
To have a out animation property.
This is least desired because on load the animation will play once for it to animate then it acts naturally afterwards.
.flipcard {
animation: return 1s forwards;
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
transition: all 0.3s ease;
}
#keyframes grow {
from {
transform: rotateY(0) scale(1);
}
to {
transform: rotateY(180deg) scale(2);
}
}
#keyframes return {
from {
transform: rotateY(180deg) scale(2);
}
to {
transform: rotateY(0) scale(1);
}
}
https://jsfiddle.net/255mnwxr/2/
You need to add #keyframes on the mouse in and out hover.
html, body {
background: #f2edea;
height: 100%;
width: 100%;
}
.container {
width: 250px;
height: 320px;
margin: auto;
position: relative;
top: 35%;
}
img {
width: 100%;
max-height: 100%;
}
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
}
#-webkit-keyframes in {
from { -webkit-transform: rotate(0deg); }
to {-webkit-transform: rotateY(180deg) scale(2);}
}
#-webkit-keyframes out {
0% { -webkit-transform: rotateY(180deg) scale(2); }
100% { -webkit-transform: rotate(0deg); }
}
.flipcard:hover {
animation: out 1s forwards;
}
.flipcard {
animation: in 1s forwards;
}
.front-side {
height: 100%;
width: 100%;
position: relative;
backface-visibility: hidden;
}
.back-side {
width: 100%;
height: 100%;
transform: rotateY(180deg);
position: absolute;
top: 0;
border-radius: 3px;
}
<div class='container'>
<div class='flipcard'>
<div class='front-side'>
<img src='https://pre00.deviantart.net/4121/th/pre/i/2018/059/6/7/brigitte_by_raikoart-dc4kzas.png'>
</div>
<div class='back-side'>
<img src="https://img00.deviantart.net/e0ec/i/2017/297/8/c/mercy_by_raikoart-dbrm54b.png">
</div>
</div>
</div>
You don't need a keyframe animation for this, you could just use basic CSS transitions for this, they'll rewind on mouseout with the transition property:
.flipcard {
transform: rotateY(0) scale(1);
transition: 1s all ease-out;
}
.flipcard:hover {
transform: rotateY(180deg) scale(2);
}
However, if you do want to use animations (for more complex interactions) I have a snippet for that at the bottom, just know this can be a little harder to maintain, and just reversing it on the default element won't work.
Also note that you may want a mouse-container that doesn't rotate but controls the hover state otherwise the mouse may fall off part way through the transition, like:
.flipcard-container:hover .flipcard {
transform: rotateY(180deg) scale(2);
}
html, body {
background: #f2edea;
height: 100%;
width: 100%;
}
.container {
width: 250px;
height: 320px;
margin: auto;
position: relative;
top: 35%;
}
img {
width: 100%;
max-height: 100%;
}
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
transform: rotateY(0) scale(1);
transition: 1s all ease-out;
}
.flipcard:hover {
transform: rotateY(180deg) scale(2);
}
.front-side {
height: 100%;
width: 100%;
position: relative;
backface-visibility: hidden;
}
.back-side {
width: 100%;
height: 100%;
transform: rotateY(180deg);
position: absolute;
top: 0;
border-radius: 3px;
}
<div class='container'>
<div class='flipcard'>
<div class='front-side'>
<img src='https://pre00.deviantart.net/4121/th/pre/i/2018/059/6/7/brigitte_by_raikoart-dc4kzas.png'>
</div>
<div class='back-side'>
<img src="https://img00.deviantart.net/e0ec/i/2017/297/8/c/mercy_by_raikoart-dbrm54b.png">
</div>
</div>
</div>
html, body {
background: #f2edea;
height: 100%;
width: 100%;
}
.container {
width: 250px;
height: 320px;
margin: auto;
position: relative;
top: 35%;
}
img {
width: 100%;
max-height: 100%;
}
#keyframes grow {
from {
transform: rotateY(0) scale(1);
}
to {
transform: rotateY(180deg) scale(2);
}
}
#keyframes shrink {
from {
transform: rotateY(180deg) scale(2);
}
to {
transform: rotateY(0) scale(1);
}
}
.flipcard {
height: 100%;
width: 100%;
margin: auto;
top: 20%;
position: relative;
box-shadow: 5px 5px 20px #94989e;
border: 3px solid #b8b8ba;
border-radius: 5px;
background: pink;
transform-style: preserve-3d;
transform: rotateY(0) scale(1);
animation: shrink 1s forwards;
}
.flipcard:hover {
animation: grow 1s forwards;
}
.front-side {
height: 100%;
width: 100%;
position: relative;
backface-visibility: hidden;
}
.back-side {
width: 100%;
height: 100%;
transform: rotateY(180deg);
position: absolute;
top: 0;
border-radius: 3px;
}
<div class='container'>
<div class='flipcard'>
<div class='front-side'>
<img src='https://pre00.deviantart.net/4121/th/pre/i/2018/059/6/7/brigitte_by_raikoart-dc4kzas.png'>
</div>
<div class='back-side'>
<img src="https://img00.deviantart.net/e0ec/i/2017/297/8/c/mercy_by_raikoart-dbrm54b.png">
</div>
</div>
</div>

CSS How to animate angled lines with skew transitions

I'm looking to incorporate a line that's being drawn that separates into 2 more spreading upwards and downwards by 45 degrees. This is CODEPEN.
CSS:
.connector {
height: 40px;
width: 200px;
border-bottom: 2px solid red;
border-right: 2px solid red;
-moz-transform: skew(-45deg);
-webkit-transform: skew(-45deg);
transform: skew(-45deg);
}
This would work:
.connector {
position: relative;
margin: 100px;
width: 100px;
height: 2px;
background: #f00;
}
.connector:before,
.connector:after {
position: absolute;
left: 100%;
top: 0;
content: '';
width: 100px;
height: 2px;
background: #f00;
transform-origin: 0 100%;
transform: rotate(-45deg);
}
.connector:after {
transform: rotate(45deg);
}
<div class="connector"></div>
Here is an animated version:
.connector {
position: relative;
margin: 100px;
width: 0;
height: 2px;
background: #f00;
animation: draw 1s linear;
animation-fill-mode: forwards;
}
.up,
.down {
position: absolute;
left: 100%;
top: 0;
content: '';
width: 0;
height: 2px;
background: #f00;
transform-origin: 0 100%;
transform: rotate(-45deg);
animation: draw 1s linear;
animation-delay: 1s;
animation-fill-mode: forwards;
}
.down {
transform: rotate(45deg);
}
#keyframes draw {
0% {
width: 0px;
}
100% {
width: 100px;
}
}
<div class="connector">
<div class="up"></div>
<div class="down"></div>
</div>
I don't know if I understood what you want. But, what about this?
https://codepen.io/pablodarde/pen/qPexVX
html
<div class="connector up"></div>
<div class="connector down"></div>
css
.connector {
height: 40px;
width: 200px;
border-right: 2px solid red;
}
.up {
border-bottom: 2px solid red;
-moz-transform: skew(-45deg);
-webkit-transform: skew(-45deg);
transform: skew(-45deg);
}
.down {
-moz-transform: skew(45deg);
-webkit-transform: skew(45deg);
transform: skew(45deg);
}
Here, my animated version...
HTML
<div class="container">
<div class="connector up"></div>
<div class="connector down"></div>
</div>
CSS
.container {
width: 0;
height: 80px;
overflow: hidden;
transition: all 2s ease;
}
.animate {
width: 220px;
}
.connector {
height: 40px;
width: 200px;
border-right: 2px solid red;
box-sizing: border-box;
}
.up {
border-bottom: 2px solid red;
-moz-transform: skew(-45deg);
-webkit-transform: skew(-45deg);
transform: skew(-45deg);
}
.down {
-moz-transform: skew(45deg);
-webkit-transform: skew(45deg);
transform: skew(45deg);
}
JavaScript
document.querySelector('.container').classList.add('animate');
setTimeout(function() {
document.querySelector('.container').classList.add('animate');
}, 500);
.container {
width: 0;
height: 80px;
overflow: hidden;
transition: all 2s ease;
}
.animate {
width: 220px;
}
.connector {
height: 40px;
width: 200px;
border-right: 2px solid red;
box-sizing: border-box;
}
.up {
border-bottom: 2px solid red;
-moz-transform: skew(-45deg);
-webkit-transform: skew(-45deg);
transform: skew(-45deg);
}
.down {
-moz-transform: skew(45deg);
-webkit-transform: skew(45deg);
transform: skew(45deg);
}
<div class="container">
<div class="connector up"></div>
<div class="connector down"></div>
</div>

Using CSS and JQuery to animate a hexagon

I created a CSS hexagon using 3 divs and border colors and sizes. I would like to animate that hexagon by flipping it on it's x-axis and getting a new css hexagon like my code, below.
That all works in CSS. But then I want the new div to scale to 2x after the flip.
The CSS transform property does everything at once so I'm trying to scale after that using jQuery animate. If possible I would be open to doing everything in jQuery.
* {
box-sizing: border-box;
}
.hexagons {
width: 1100px;
letter-spacing: 0;
font-size: 0;
margin: 0 auto;
}
.hexagon-holder {
position: relative;
margin: 0 21.5px;
width: 226px;
height: 130.48px;
display: inline-block;
letter-spacing: 0;
font-size: 0;
}
.hexagon {
position: relative;
width: 226px;
height: 130.48px;
background-image: url(http://csshexagon.com/img/meow.jpg);
background-size: auto 258.6529px;
background-position: center;
border-left: solid 1px #333333;
border-right: solid 1px #333333;
display: inline-block;
z-index: 1;
}
.hexagon .hexTop,
.hexagon .hexBottom {
position: absolute;
z-index: 1;
width: 159.81px;
height: 159.81px;
overflow: hidden;
-webkit-transform: scaleY(0.5774) rotate(-45deg);
-ms-transform: scaleY(0.5774) rotate(-45deg);
transform: scaleY(0.5774) rotate(-45deg);
background: inherit;
left: 32.10px;
-webkit-backface-visibility: hidden
}
/*counter transform the bg image on the caps*/
.hexagon .hexTop:after,
.hexagon .hexBottom:after {
content: "";
position: absolute;
width: 224.0000px;
height: 129.32646029847618px;
-webkit-transform: rotate(45deg) scaleY(1.7321) translateY(-64.6632px);
-ms-transform: rotate(45deg) scaleY(1.7321) translateY(-64.6632px);
transform: rotate(45deg) scaleY(1.7321) translateY(-64.6632px);
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
background: inherit;
}
.hexagon .hexTop {
top: -79.9031px;
border-top: solid 1.4142px #333333;
border-right: solid 1.4142px #333333;
}
.hexagon .hexTop:after {
background-position: center top;
}
.hexagon .hexBottom {
bottom: -79.9031px;
border-bottom: solid 1.4142px #333333;
border-left: solid 1.4142px #333333;
}
.hexagon .hexBottom:after {
background-position: center bottom;
}
.hexagon:after {
content: "";
position: absolute;
top: 0.5774px;
left: 0;
width: 224.0000px;
height: 129.3265px;
z-index: 2;
background: inherit;
}
.hexagon:nth-child(7n-2) {
margin-left: 156px;
}
.hexagon:nth-child(n+5) {
margin-top: 29px;
}
.hexText {
position: absolute;
left: 0;
top: 0;
z-index: 3;
color: #000;
opacity: 1;
font-size: 20px;
text-align: center;
width: 100%;
color: #fff;
}
/* entire container, keeps perspective */
.flip-container {
perspective: 1000;
transform-style: preserve-3d;
width: 226px;
height: 280.48px !important;
background: transparent;
}
/* UPDATED! flip the pane when hovered */
.flip-container:hover .back {
transform: rotateY(0deg);
}
.flip-container:hover .front {
transform: rotateY(180deg);
}
.flip-container,
.front,
.back {
width: 226px;
height: auto;
}
/* flip speed goes here */
.flipper {
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
top: 75px;
}
/* hide back of pane during swap */
.front,
.back {
backface-visibility: hidden;
transition: 0.6s;
transform-style: preserve-3d;
position: absolute;
top: 0;
left: 0;
}
/* UPDATED! front pane, placed above back */
.front {
z-index: 2;
transform: rotateY(0deg);
}
/* back, initially hidden pane */
.back {
transform: rotateY(-180deg);
}
/*
Some vertical flip updates
*/
.vertical.flip-container {
position: relative;
}
.vertical .back {
transform: rotateX(180deg);
}
.vertical.flip-container:hover .back {
transform: rotateX(0deg);
}
.vertical.flip-container:hover .front {
transform: rotateX(180deg);
}
.hexagon-overlay {
position: absolute;
width: 226px;
height: 130.48px;
margin: 0;
background-color: teal;
background-size: auto 247.1059px;
background-position: center;
border-left: solid 6px #333333;
border-right: solid 6px #333333;
opacity: .7;
z-index: 3;
top: 0;
left: 0;
}
.hexagon-overlay .hexTop,
.hexagon-overlay .hexBottom {
position: absolute;
z-index: 1;
width: 159.81px;
height: 159.81px;
overflow: hidden;
-webkit-transform: scaleY(0.5774) rotate(-45deg);
-ms-transform: scaleY(0.5774) rotate(-45deg);
transform: scaleY(0.5774) rotate(-45deg);
background: inherit;
left: 27.10px;
}
/*counter transform the bg image on the caps*/
.hexagon-overlay .hexTop:after,
.hexagon-overlay .hexBottom:after {
content: "";
position: absolute;
width: 214.0000px;
height: 123.55295760657991px;
-webkit-transform: rotate(45deg) scaleY(1.7321) translateY(-61.7765px);
-ms-transform: rotate(45deg) scaleY(1.7321) translateY(-61.7765px);
transform: rotate(45deg) scaleY(1.7321) translateY(-61.7765px);
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
background: inherit;
}
.hexagon-overlay .hexTop {
top: -79.9031px;
border-top: solid 8.4853px #333333;
border-right: solid 8.4853px #333333;
}
.hexagon-overlay .hexTop:after {
background-position: center top;
}
.hexagon-overlay .hexBottom {
bottom: -79.9031px;
border-bottom: solid 8.4853px #333333;
border-left: solid 8.4853px #333333;
}
.hexagon-overlay .hexBottom:after {
background-position: center bottom;
}
.hexagon-overlay .hexagon:after {
content: "";
position: absolute;
top: 3.4641px;
left: 0;
width: 214.0000px;
height: 123.5530px;
z-index: 2;
background: inherit;
}
<div class="hexagons">
<div class="hexagon-holder flip-container" ontouchstart="this.classList.toggle('hover');">>
<div class="flipper">
<div class="front">
<div class="hexagon">
<div class="hexTop"></div>
<div class="hexBottom"></div>
</div>
</div>
<div class="back">
<div class="hexagon-overlay">
<div class="hexTop"></div>
<div class="hexBottom"></div>
</div>
<div class="hexText">LifePoint Dental
<br />+</div>
<div class="hexagon" style="transform:scaleX(-1);">
<div class="hexTop"></div>
<div class="hexBottom"></div>
</div>
</div>
</div>
</div>
</div>
View on Codepen

How to draw heart with text in middle?

I found this answer "css: how to draw circle with text in middle?" , but I need the same, but with a heart shape. I found a lot of heart shape figures online, but none of this with text inside. At the same time, I need the heart only with borders, and when click, filled the background.
My code until now:
.heart {
width: 100px;
height: 90px;
font-size: 50px;
color: #fff;
line-height: 100px;
text-align: center;
}
.heart:before,
.heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
.heart:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin: 100% 100%;
}
<div class="heart">Heart</div>
In order to get text to appear on the heart, you need to set the heart container as relative and the text inside of it as absolute as shown below.
I set the border of the :before and :after to give the heart a border.
The toggling of the fill uses functionality from YouMightNotNeedJQuery.com.
function toggleFill(heart, className) {
if (!hasClass(heart, className)) {
addClass(heart, className);
} else {
removeClass(heart, className);
}
}
function addClass(el, className) {
if (el.classList) {
el.classList.add(className);
} else {
el.className += ' ' + className;
}
}
function removeClass(el, className) {
if (el.classList) {
el.classList.remove(className);
} else {
el.className = el.className.replace(
new RegExp('(^|\\b)' + className.split(' ').join('|') +
'(\\b|$)', 'gi'), ' ');
}
}
function hasClass(el, className) {
if (el.classList) {
return el.classList.contains(className);
} else {
return new RegExp('(^| )' + className +
'( |$)', 'gi').test(el.className);
}
}
.unselectable {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.filled:before,
.filled:after {
background: red !important;
}
#wrapper {
width: 300px;
height: 180px;
background: #444;
}
.heart {
position: relative;
top: calc(50% - 45px); /* 1/2 height of wrapper - 1/2 height of heart */
left: calc(50% - 50px); /* 1/2 width of wrapper - 1/2 width of heart */
width: 100px;
height: 90px;
}
.heart:before,
.heart:after {
position: absolute;
content: "";
top: 0px;
width: 50px;
height: 80px;
background: inherit;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
}
.heart:before {
left: 50px;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
border-left: 2px solid red;
border-top: 2px solid red;
border-bottom: 1px solid red;
}
.heart:after {
left: 0px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin: 100% 100%;
border-right: 2px solid red;
border-top: 2px solid red;
border-bottom: 1px solid red;
}
.heart-text {
position: absolute;
top: 0;
left: calc(50px - 30px); /* 1/2 width of heart - 1/2 width of text */
z-index: 100;
line-height: 66px;
text-align: center;
font-size: 24px;
font-weight: bold;
color: #FFF;
}
<div id="wrapper">
<div class="heart" onclick="toggleFill(this, 'filled')">
<div class="heart-text unselectable">
Heart
</div>
</div>
</div>
A quick search and there is a good article about creating shapes with CSS over # css-tricks.com that can be seen here.
If we take the example of how to create a heart and extend upon it a little we can get the following snippet that gives you a heart that starts out simply as a border;
(function(){
var heart = document.querySelector('#heart');
heart.addEventListener('click', function(e) {
this.className += ' is--filled'
});
}());
#heart {
position: relative;
width: 100px;
height: 90px;
text-align: center;
font-size: 16px;
position: relative;
}
#heart span {
width: 100%;
display: block;
top: 50%;
margin-top: -16px;
line-height: 16px;
left: 0;
right: 0;
position: absolute;
z-index: 1;
}
#heart.is--filled:before,
#heart.is--filled:after {
background-color: red;
}
#heart:before,
#heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
border: 1px solid red;
transition: background-color .25s ease 0s;
-webkit-transition: background-color .25s ease 0s;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
#heart:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin :100% 100%;
}
#heart:before {
border-right: none;
border-bottom: none;
}
#heart:after {
border-left: none;
border-bottom: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id='heart'>
<span>Hey</span>
</div>
</body>
</html>
However, as someone else has mentioned in the comments it may be an easier approach to use images or the canvas element. I say this purely because it may prove difficult to get just the heart border you desire before clicking the heart (easier to see if you run the snippet). You could opt for much softer opaque background color before you click and then transition to red maybe?
Hope this helps you out!
Use pseudo elements of css3.
.text {
position: absolute;
color: #eee;
z-index: 99;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
}
#heart {
position: relative;
width: 100px;
height: 90px;
}
#heart:before,
#heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
#heart:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin: 100% 100%;
}
<div id="heart">
<div class="text">ABC</div>
</div>
Use this
HTML
$('#change').click(function() {
var className = $(this).attr('class');
if(className == "heart"){
$(this).removeClass('heart');
$(this).addClass('heart1');
}
else{
$(this).removeClass('heart1');
$(this).addClass('heart');
}
});
.txt{
z-index:1;
font-size: 20px;
color: #000;
position:relative;
text-align:center;
top:15px;
right:5px;
}
.heart {
width: 100px;
height: 90px;
}
.heart1 {
width: 100px;
height: 90px;
}
.heart:before,
.heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: yellow;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
.heart1:before,
.heart1:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
.heart1:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin: 100% 100%;
}
.heart:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin: 100% 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="change" class="heart"><div class="txt">Heart</div></div>

Categories