I want to create a border animation for a button element. The design is that the ends of the slanted rectangle are open and then close on hover.
This is what we're trying to do (excuse my artistic "style"):
Here's some code and a codepen example:
a svg rect {
stroke: red;
stroke-width: 5;
transition: 1s;
stroke-dasharray: 100%;
stroke-dashoffset: 0;
}
a:hover svg rect {
stroke-dasharray: 0%;
stroke-dashoffset: 0;
}
codepen example
I'm having trouble understanding the math behind stroke-dasharray, but it seems this should be possible without too much complex math.
The other issue is that it would need to be responsive. So the button can contain different amounts text.
Let me know if you need further clarification.
Here is, I think, about the best you can do to create an automatically responsive button that meets your requirements.
It has a couple of failings:
The gap in the outline of the button varies in size based on the label length.
It needs a fairly recent browser (in order to support pathLength on a <rect> element)
.btn {
display: inline-block;
position: relative;
overflow: auto;
}
.btn + .btn {
margin-left: 20px;
}
.btn svg {
position: absolute;
top: 0;
left: 0;
}
.label {
position: relative;
font-size: 18px;
font-weight: bold;
padding: 5px 20px;
}
.btn, .btn svg {
overflow: visible;
}
.btn svg rect {
fill: gold;
stroke: black;
stroke-width: 2px;
stroke-dasharray: 47 3;
transform-origin: 50% 50%;
transform-box: fill-box;
transform: skewX(-10deg) scale(1, -1);
transition: all 0.75s;
}
.btn:hover svg rect {
stroke-dasharray: 50 0;
stroke-dashoffset: 50;
}
<div class="btn">
<svg width="100%" height="100%">
<rect width="100%" height="100%" pathLength="100"/>
</svg>
<div class="label">Button</div>
</div>
<div class="btn">
<svg width="100%" height="100%">
<rect width="100%" height="100%" pathLength="100"/>
</svg>
<div class="label">Much longer button</div>
</div>
Instead of using a skewed svg element I'm using a polygon. This way I can calculate the total length (perimeter length) of the polygon. I've done this using javascript: console.log(poly.getTotalLength()). This gave me 543.7. For the polygon's stroke-dasharray I'm using 250, 21.85 where 250 + 21.85 = 543.7 / 2.
I'm animating the stroke-dashoffset to 543.7 / 2 = 271.85; and stroke-dasharray to 271.85 0. (the stroke goes from 250 to 271.85 and the gap from 21.85 to 0)
Another change I've made: I'm using a svg <a> element instead of the one you are using and the polygon has pointer-events:all; I've added this to make it sensitive to the mouse although the fill:none.
I hope you'll find this useful.
polygon {
stroke: red;
stroke-width: 4;
stroke-dasharray:250, 21.85;
fill: none;
transition: 1s;
pointer-events:all;
}
polygon:hover{
stroke: #ff0;
stroke-dashoffset: 271.85;
stroke-dasharray: 271.85 0;
}
<svg viewBox = "0 0 250 50" width="250">
<a xlink:href="#" class="py-2 px-5">
<text x="125" y="30" text-anchor="middle">Button Button Button</text>
<polygon id="poly" points="2,48 220,48 248,2 30,2 2,48" />
</a>
</svg>
Related
I tried to adapt a codepen thing for waves with svgs.
Works just fine in Chrome, Safari and Edge, but not in Firefox (and IE, but I don't care too much about that).
I suspect some Syntax problem with the svg. The animation works just fine, but the svgs are not displayed correctly. In Firefox it's just a straight line instead of waves.
Anyone out there, that has an idea about that?
Thanks a lot in advance.
.waves {
width: 100%;
height: 7em;
position: relative;
overflow: hidden;
background-color: #f6f9fc;
}
.wave
{
width:calc( 100% + 4em );
height:100%;
position:absolute;
left:-2em;
background:bottom center repeat-x;
animation-iteration-count:infinite;
animation-timing-function:linear;
}
/* Individual wave layers */
.wave_1
{
animation-name:wave_1;
animation-duration:3400ms;
animation-delay:-1200ms;
z-index:2;
opacity: 1;
background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="2000" viewBox="0 0 600 2000"><path fill-rule="evenodd" clip-rule="evenodd" fill="#fff" d="M600 2000c-100.8 0-141.6-39.892-240-39.892S98.4 2000 0 2000V0h6000v2000z"/></svg>');
background-position:bottom left;
background-color: #e0e7f1;
top: -3em;
}
.wave_2
{
z-index:1;
opacity: 1;
background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="2000" viewBox="0 0 600 2000"><path fill-rule="evenodd" clip-rule="evenodd" fill="#e0e7f1" d="M600 2000c-100.8 0-141.6-39.892-240-39.892S98.4 2000 0 2000V0h6000v2000z"/></svg>');
background-position:bottom left;
background-color: #245aa6;
top: 0em;
}
#keyframes wave_1
{
from { transform: rotate(0deg) translatey(-0.61em) rotate(0deg) ; }
to { transform: rotate(360deg) translatey(-0.61em) rotate(-360deg) ; }
}
<div class="waves">
<div class="wave wave_1"></div>
<div class="wave wave_2"></div>
</div>
How can I draw a border-right in a box using CSS3 like in this image?
One possible solution would be this,
#curve{
margin:0 auto;
position:relative;
width:50px;
height:50px;
border-top:1px solid red;
border-right:1px solid red;
border-top-right-radius:50px;
float:left;
margin-left:50px;
}
#curve:after{
content: "";
position: absolute;
width: 50px;
height: 50px;
border-bottom: 1px solid red;
border-left: 1px solid red;
border-bottom-left-radius: 50px;
left: 50px;
top: 50px;
}
<div id="curve"></div>
SVG is much better option to create such kind of shapes. It is simple and scale able.
We can use SVG's path element to create this shape and fill it with some color, gradient or 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.
Below is the necessary code to create this shape:
<path d="M10,10
L210,10
Q230,10 250,50
T290,90
L10,90
Z" />
I've used 5 commands inside path element. Below is a brief description:
M command is used to define the starting point. It appears at the beginning and specify the point from where drawing should start.
L command is used to draw straight lines.
Q command is used to draw curves.
T produces the same type of curve as earlier, but if it follows another Q command or a T command.
Z command is used to close the current path.
Output:
Working Example:
body {
background: linear-gradient(#466273, #5c8ea8) no-repeat;
min-height: 100vh;
margin: 0;
}
<svg width="300" height="100" viewBox="0 0 300 100">
<path d="M10,10 L210, 10 Q230,10 250,50 T290,90 L10,90 Z" stroke="#000" stroke-width="2" fill="yellowgreen" />
</svg>
Useful Resources:
SVG: Specs, MDN
I'm trying to make a custom follower alert for Twitch TV. And I'm trying to centre a small image inside a div. So far I've managed to centre it horizontaly but no matter what I try it will not centre vertically. I'm not sure why, i've tried reading many other questions on stackoverflow already, as well as following a guide from W3schools but I think this is more of a specific problem to my code. Here is a fiddle. (You can't see the image but you can see where the image would be)
And here is the code; with the idea being that the image is centered both horizontally and vertically inside the small blue square, which i've named 'left-square-container'. However currently the image is horizontally centered at the top of the div only.
If anyone can help I'd appreciate it.
#keyframes slideInFromAbove {
0% {
transform: translateY(-100%);
}
6% {
transform: translateY(0);
}
98% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
#keyframes slideInFromTheLeft {
0% {
opacity: 1;
transform: translateX(-100%);
}
4.4% {
opacity: 1;
transform: translateX(0);
}
97% {
opacity: 1;
transform: translateX(0);
}
100% {
opacity: 0;
transform: translateX(-100%);
}
}
#keyframes slideInFromBelow {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0);
}
}
#keyframes slideInFromTheLeft-Text {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
.follower-container {
display: flex;
font-family: 'Roboto';
position: absolute;
overflow: hidden;
/*hide elements when they overflow*/
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
.left-square-container {
width: 100px;
height: 100px;
background: #0d47a1;
position: relative;
display: inline-block;
float: left;
z-index: 1;
transform: translateX(-100%);
animation: 9.6s 1 slideInFromAbove;
/* timing (.4s duration + 8s hold + .4s removal of self + animation of right + removal of right) */
-webkit-animation-fill-mode: forwards;
/* Safari 4.0 - 8.0 */
animation-fill-mode: forwards;
}
.icon img
/*THIS IS THE DIV TO CHANGE THE IMAGE ALIGNMENT*/
{
display: block;
margin: 0 auto;
webkit-filter: drop-shadow(1px 1px 1px #212121);
filter: drop-shadow(1px 1px 1px #212121);
}
.right-retangle-container {
width: 400px;
height: 100px;
opacity: 0;
background: #292929;
border-top: 5px solid #0d47a1;
box-sizing: border-box;
display: inline-block;
float: left;
position: relative;
/* needed for z-index*/
z-index: 0;
/*place under left square*/
transform: translateX(-100%);
animation: 8.8s .6s 1 slideInFromTheLeft;
/* timing (.5 initial animation duration + 8s hold + .3s removal of self) additional .6s of delay for animation of left square*/
-webkit-animation-fill-mode: forwards;
/* Safari 4.0 - 8.0 */
animation-fill-mode: forwards;
}
.text {
font-size: 30px;
color: #ffffff;
overflow: hidden;
text-align: center;
/*vertical alignment of text*/
position: relative;
/*horizontal alignment of text*/
top: 50%;
/*horizontal alignment of text*/
transform: translateY(-50%);
/*horizontal alignment of text*/
}
.text-animation {
transform: translateY(100%);
animation: .5s 1s 1 slideInFromBelow;
-webkit-animation-fill-mode: forwards;
/* Safari 4.0 - 8.0 */
animation-fill-mode: forwards;
margin-left: 20px;
margin-right: 20px;
}
.keyword:not(.user_message) {
color: #f57f17;
}
<div class="follower-container">
<div class="left-square-container">
<div class="icon">
<img class="image" src="{image}" />
</div>
</div>
<div class="right-retangle-container">
<div class="text">
<div class="text-animation">
New Follower <span class='keyword name'>{name}</span></div>
</div>
</div>
</div>
There are several ways to do this, but since you're already using flexbox, I would recommend continuing with that path.
On your .left-square-container div, simply change display to display:flex and then set align-items: center; and justify-content: center;.
Seems to work for me.
Fiddle
If you know the height of the container, you can set the line-height of said container to the value of its height.
I updated your CSS to look like so:
.icon {
text-align: center;
heignt: 100px;
line-height: 100px;
}
The "icon" div does not have any specified height. It is declared block. Hence, you cannot expect to align an image inside this div vertically as the scope of the div height-wise on the screen will be only of the size of the image.
Even in the in css of "icon", you have said margin:0 auto; -> The command will align the image in center not vertically but only horizontally. For what you want to happen, that 0 should be auto and then there should be some height of the div to see it align in the center vertically as well.
For example I want to add a custom html object to wold map by gps coords (lat, lng) - like pulsating dot done with css or any other(js?) marker animation
<style>
#circle {
background: red;
width: 10px;
height: 10px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
}
.gps_ring {
border: 3px solid red;
-webkit-border-radius: 30px;
height: 18px;
width: 18px;
left:20px;
top:214px;
-webkit-animation: pulsate 1s ease-out;
-webkit-animation-iteration-count: infinite;
opacity: 0.0
}
#-webkit-keyframes pulsate {
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
50% {opacity: 1.0;}
100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
}
</style>
<div id="state" class="grid_4 alpha">
<div class="gps_ring"></div>
</div>
You can get x, y coordinates from projection:
var projection = d3.geo.mercator()
.center([0, 5 ])
.scale(150);
projection([long, lat]);
For animation you could either use either d3 transitions example or CSS.
I have created a block for you: http://bl.ocks.org/ckothari/32149f15261b9c5c7a56c40f7f6b353d
EDIT
Sorry, just realized your question was about using http://datamaps.github.io/. Let me know if you can use topojson, else i will delete my answer.
EDIT-2
To color country:
d3.tsv('data.csv', function(data){
g.selectAll('path')
.filter(function(d){
return data.find(function(d1){
return d1.iso == d.properties.iso_a2;
})
})
.attr('class', 'selected');
//...
})
EDIT-3 Chaining transitions
Updated example: https://bl.ocks.org/ckothari/raw/32149f15261b9c5c7a56c40f7f6b353d/
Also see http://bl.ocks.org/mbostock/1125997.
<div class="box">
<div class="pic">
<img src="/images/img.png" class="img_pic" />
</div>
</div>
.box {
border: 1px solid #333;
cursor: pointer;
height: 73px;
margin: 40px 42px 0 0;
width: 269px;
}
.img_pic {
display: block;
margin-left: auto;
margin-right: auto;
}
I want the image ("img_pic") to be centered vertically as well. With what I have I can do it horizontally but not vertically. I tried vertical-align: middle; but that didn't work and I tried line-height: 73px since the height of the box is 73px. I can't seem to figure a way out of this.
How can I center the image vertically while still retaining the horizontal centering?
Don't make the image a block element. As an inline element you can center it as text. Then set the line height to the same as the box, and set vertical alignment on the image to middle to put it in the middle of the text line:
.box {
border: 1px solid #333;
cursor: pointer;
height: 73px;
margin: 40px 42px 0 0;
width: 269px;
text-align: center;
line-height: 73px;
}
.img_pic {
vertical-align: middle;
}
Demo: http://jsfiddle.net/AwgNy/
You cannot vertical-align block elements.
If you know the height of the image you could put an equal top and bottom margin on .img_plc or an equal top and bottom padding on `.box.'
As you've said it's variable height, then you can use display: table-cell for .box with vertical-align: middle;
If you know the dimensions of the image you can do it in the css and either use margin to push it down:
margin-top:/*(box height / 2) - (image height / 2)*/;
or use relative and absolute positioning:
.box
{
position:relative;
/*other code*/
}
.image_pic
{
position:absolute;
top:/*(box height / 2) - (image height / 2)*/;
}
If you cannot guarantee the dimensions of the image then you should use javascript/jQuery to get the image height and use the same formula as above for working out the offset. Then still using javascript/jQuery, edit the css for the image to set the offset for margin-top or top.
Just Use This CSS DEMO HERE
.box {
border: 1px solid #333;
cursor: pointer;
height: 73px;
margin: 40px 42px 0 0;
width: 269px;
position:relative
}
.img_pic {
display: block;
position:absolute;
top:0px;
left:0px;
right:0px;
bottom:0px;
margin:auto
}