How does the `a` tag behave? - html

Could you explain how the a tag behaves in this example? Why is it so small?
a {
border: 1px solid currentColor;
}
<li>
<a href="https://facebook.com/starbucks">
<svg aria-hidden="true" class="valign-middle absoluteCenter" focusable="false" preserveAspectRatio="xMidYMid meet">
<path></path>
<circle class="sb-icon-hover" cx="50%" cy="50%" fill="transparent" r="75%"></circle>
</svg>
</a>
</li>
Also, could you explain, how to fix it? And how to center it inside the block? Thank you!

The anchor element (<a>) is by default an inline element. It will have the height of the font (example 1). So, making a border around it will display the height of the font.
If you set the display of the <a> to inline-block or block (example 2 and 3) the element will "contain" the child elements (except if you limit the height...). With either one you can set properties like border, background, padding, margin etc.
svg {
display: inline; /*default*/
height: 2em;
vertical-align: bottom;
}
a {
border: 1px solid currentColor;
}
ul li:nth-child(1) a {
display: inline; /*default*/
}
ul li:nth-child(2) a {
display: inline-block;
}
ul li:nth-child(3) a {
display: block;
}
li {
margin: .1em;
}
<ul>
<li>
<a href="https://facebook.com/starbucks">default
<svg viewBox="0 0 100 100">
<circle cx="50%" cy="50%" fill="red" r="50%"/>
</svg>
</a>
</li>
<li>
<a href="https://facebook.com/starbucks">inline-block
<svg viewBox="0 0 100 100">
<circle cx="50%" cy="50%" fill="red" r="50%"/>
</svg>
</a>
</li>
<li>
<a href="https://facebook.com/starbucks">block
<svg viewBox="0 0 100 100">
<circle cx="50%" cy="50%" fill="red" r="50%"/>
</svg>
</a>
</li>
</ul>

Related

How can I center scaled radio button icons in their DIV?

The "logo" appearing as a yellow SVG circle below can be scaled by adjusting the height ratio (line indicated by <==== (1) in the code), enabling tuning without modifying the SVG itself.
But even though .left_center_myicon is mostly duplicated in .right_center_myicon, the same tuning in <==== (2) does not affect the radio button icons.
How can I center scaled radio button icons in their DIV? I'm using here inline SVGs as even changing them to be linked (from <svg> to <img src="xyz.svg"> is itself a brittle and subtle change. If you see that difficulty, please switch to linked SVGs in your answer.
Update
I'd like the radio buttons to be vertically centered in their div, while that div is itself vertically centered and right justified in the header.
Ideally, I'd also like to be able to adjust the scale of the SVG radio button icons from the style file (although I'm starting to wonder whether doing so might be going against the grain of established custom—in other words, I'm wondering if perhaps designers end up editing the SVG files rather than manipulating the scale of the SVGs from CSS).
.header {
width: 100%;
height: 300px;
background-color: #ddd;
margin: 5px;
align-items:center;
display: block;
text-align: center;
}
.left_center_myicon {
margin: 0 auto;
background-color: #bbb;
float: left;
height: 70%; /* <==== (1) */
position: relative;
top: 50%;
left: 0;
transform: translate(0%, -50%);
}
.right_center_myicon {
background-color: #ccc;
margin: 0 auto;
float: right;
height: 70%; /* <==== (2) */
position: relative;
top: 50%;
left: 0;
transform: translate(0%, -50%);
vertical-align: middle;
}
svg { stroke:black; stroke-width:5; opacity:0.5; vertical-align: middle; }
<div class="header">
<a href="index.html">
<img class="left_center_myicon" src="svg/logo.svg"/>
</a>
<div class="right_center_myicon">
<label class="myLabel">
<input type="radio" name="radioGroup" class="myradioG" checked>
<svg width="100" height="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="30" style="fill:blue;" />
</svg>
</label>
<label class="inline-radio">
<input type="radio" name="radioGroup" class="myradioG">
<svg width="100" height="100" viewBox="0 0 100 100">
<rect x="20" y="20" rx="15" ry="15" width="60" height="60" style="fill:red;" />
</svg>
</label>
</div>
</div>
The content of logo.svg is:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="160" height="120"
viewBox="0 0 160 120"
version="1.1">
<g>
<circle cx="80" cy="60" r="50" fill="yellow" stroke="blue" stroke-width="10" />
</g>
</svg>
When in doubt, flexbox all the things. And add some wrappers... and a spacer.
I find CSS float maddening to work with, so I avoid it like the plague. And to answer your other question, whenever possible I include my svgs inline so the inner components can still be targeted/styled with CSS. This approach should work with either though.
I tried making a fiddle but couldn't get even the simplest code to work or display anything, so I'm not sure if that's me or them.... Works great locally in my browser though. https://imgur.com/AWrWK8Z
I made 2 additions, a middle spacer element set to flex grow so it takes up all the available space it can, pushing the other elements far to the right/left. And wrappers around the input/label pairs (and the lone left guy). I used flex on both the header container and the right and left child containers, to simplify vertical centering.
.header {
width: 100%;
height: 300px;
display: flex;
align-items: center;
background-color: #ddd;
}
.spacer {
flex: 1 0 auto;
background: rgba(200,200,200,1);
}
.left {
background-color: #bbb;
}
.right {
background-color: #ccc;
}
.wrapper {
display: flex;
height: 70%;
align-items: center;
outline: 1px solid blue;
}
.wrapper > div {
flex: 1 1 auto;
outline: 1px solid black;
}
<div class="header">
<div class="left wrapper">
<div>
<a>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="160" height="120"
viewBox="0 0 160 120"
version="1.1">
<g>
<circle cx="80" cy="60" r="50" fill="yellow" stroke="blue" stroke-width="10" />
</g>
</svg>
</a>
</div>
</div>
<div class="spacer"></div>
<div class="right wrapper">
<div>
<label class="myLabel">
<input type="radio" name="radioGroup" class="myradioG" checked>
<svg width="100" height="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="30" style="fill:blue;" />
</svg>
</label>
</div>
<div>
<label class="inline-radio">
<input type="radio" name="radioGroup" class="myradioG">
<svg width="100" height="100" viewBox="0 0 100 100">
<rect x="20" y="20" rx="15" ry="15" width="60" height="60" style="fill:red;" />
</svg>
</label>
</div>
</div>
</div>

Extra pixels when element is inline

I am struggling to understand how the calculation of width/height in inline elements works. My question is very similar to this Extra pixels are being added to the span element yet slightly different.
There is a div element of size 50x50. Within the div, there is a span with padding 15px. The span contains SVG circle of size 20x20.
So there are three use cases:
Only div is a block
div - size 50x50 ✔️
span - size: 50x47 ❌ where are those three pixels?
svg - size: 20x20 ✔️
div and span is a block
div - size 50x50 ✔️
span - size: 50x54 ❌ where do these 4 pixels come from?
svg - size: 20x20 ✔️
eveything is a block
div - size 50x50 ✔️
span - size: 50x50 ✔️
svg - size: 20x20 ✔️
span {
/* display: block; */
padding: 15px;
}
div {
height: 50px;
width: 50px;
}
svg {
/* display: block; */
height: 20px;
width: 20px;
}
<div>
<span>
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
</div>
CodePen is available here.
Note: I tried it in the latest Chrome but I think it will be the same everywhere. It's probably just some fundamental thing I am missing. :)
Your second case is covered here: Image inside div has extra space below the image. Due to the default alignment you will have extra space under your SVG. This can be fixed by adding display:block like you discovered or by adding vertical-align:top which is more logical as solution:
span {
display: block;
padding: 15px;
outline:1px solid green;
}
div {
height: 50px;
width: 50px;
margin:30px;
outline:1px solid blue;
}
svg {
height: 20px;
width: 20px;
outline:1px solid red;
}
<div>
<span>
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
</div>
<div>
<span>
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg" style="vertical-align:top;"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
</div>
Your first case is a bit tricky because it has nothing to do with the SVG or the width/height you are setting. It's all about font metrics.
To simplify let's remove the div around and consider different SVG inside the same span and without padding:
span {
border: 1px solid green;
margin:0 10px;
}
svg {
outline: 1px solid red;
}
<span>
<svg
viewBox="0 0 24 24" height="20"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="30"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="50"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="200"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
Notice how the span has always the same height whataver the SVG inside due to the nature of inline element. Let's increase the font-size
span {
border: 1px solid green;
margin:0 10px;
}
svg {
outline: 1px solid red;
}
body {
font-size:40px;
}
<span>
<svg
viewBox="0 0 24 24" height="20"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="30"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="50"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
<span>
<svg
viewBox="0 0 24 24" height="200"
xmlns="http://www.w3.org/2000/svg"
>
<circle
strokeLinecap="butt"
strokeDasharray="64"
cx="12"
cy="12"
r="9"
/>
</svg>
</span>
The span are now bigger in height and the SVG are kept the same. You will also note the small gap at the bottom of the SVG due to the alignment I explained previously. Try to add font-size:0 and see the result.
As you can see the height of your span has nothing to do with the SVG. To that height, you add the vertical padding to get the final height. In your case, the height was 17px and adding the padding you will have 47px which is close to 50px but there is no relation with.
Note that you may get a different result than 47px if you test in different browsers/OS since the font will not for sure be the same and the initial height can vary.
If you check the speficiation you can read:
The 'height' property does not apply. The height of the content area should be based on the font ...
The vertical padding, border and margin of an inline, non-replaced box start at the top and bottom of the content area,
Making the span block element will change this behavior and you will have a more intuitive result as you noticed in your last example: 2*15px of padding + 20px of SVG height.
Related question with more detail in order to understand how the height of element are calculated: How to determine height of content-box of a block and inline element
Another related question: Can specific text character change the line height?

How can I align svg circle in the middle of the div?

I need to make a circle emulating the button for closing the window in the Mac OS. But when I try to move it lower, svg's border cuts it off. How can I move the border to place the circle directly in the middle of the panel (vertically)?
JSFiddle: https://jsfiddle.net/sm6r0kvn/2/
<div class="panel">
<svg viewbox="0 0 20 17" width="20" heigth="50"><circle r="7" cx="14" cy="9.5" fill="#fc615e"/></svg>
</div>
You can set your viewbox like <svg viewbox="0 0 20 20" width="20" heigth="20"> and then set cx and cy 50%. If you want to center it in the panel vertically just make it a flexbox and add align-items: center - see demo below:
.block {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
max-width: 550px;
min-width: 480px;
width: 80vw;
height: 200px;
background: black;
border-radius: 10px 10px 5px 5px;
}
.panel {
background-color: #e0e0e0;
border-radius: 5px 5px 0 0;
display: flex; /* added */
align-items: center; /* added */
}
.text {
color: white;
padding: 5px;
}
<div class="block">
<div class="panel">
<svg viewbox="0 0 20 20" width="20" heigth="20">
<circle r="7" cx="50%" cy="50%" fill="#fc615e"/>
</svg>
</div>
<div class="text">
Text here
</div>
</div>
This is because you are drawing your cicrcle outside of the svg viewbox. You can either use CSS to move whole svg box or make it larger
svg {
border: 1px blue solid;
}
.panel.moved {
margin-left: 100px;
}
<div class="panel">
<svg viewbox="0 0 20 20" width="200" heigth="200">
<circle r="10" cx="10" cy="10" fill="#fc615e"/>
</svg>
</div>
<div class="panel">
<svg viewbox="0 0 20 20" width="200" heigth="200">
<circle r="10" cx="20" cy="10" fill="#fc615e"/>
</svg>
</div>
<div class="panel">
<svg viewbox="0 0 30 20" width="300" heigth="200">
<circle r="10" cx="20" cy="10" fill="#fc615e"/>
</svg>
</div>
<div class="panel moved">
<svg viewbox="0 0 20 20" width="200" heigth="200">
<circle r="10" cx="10" cy="10" fill="#fc615e"/>
</svg>
</div>

Extra vertical space on SVG

I have a 16x16px SVG with 10px of padding and 1px border and for some reason, the height is 40px instead of 38px, like the width (on my local site, it's actually 36.95x44px). What can I do to eliminate this extra space and achieve a perfect square?
.layout-toggle {
display: inline-block;
padding: 10px;
border: 1px solid grey;
}
.layout-toggle.layout-active {
background-color: black;
}
.layout-toggle.layout-active svg {
fill: white;
width: 1em;
height: 1em;
}
.layout-toggle .layout-icon {
width: 1em;
height: 1em;
vertical-align: middle;
}
<a href="#">
<div class="layout-toggle">
<svg class="layout-icon" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" viewbox="0 0 17 16" style="enable-background:new 0 0 17 16;" xml:space="preserve">
<g>
<g>
<g id="calendar-view-01">
<g>
<g id="Calender-Layout-Icon_no-border-1">
<path d="M0.3,0h4v4h-4V0z M0.3,6h4v4h-4V6z M0.3,12h4v4h-4V12z M6.3,0h4v4h-4V0z M6.3,6h4v4h-4V6z M6.3,12h4v4h-4
V12z M12.3,0h4v4h-4V0L12.3,0z M12.3,6h4v4h-4V6L12.3,6z M12.3,12h4v4h-4V12L12.3,12z" />
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
</a>
http://codepen.io/ourcore/pen/rjLmRM
That is because your <svg> element is displayed inline by default. If you explicitly declare display: block on the element, the height will compute correctly.
When inline display is active, the element will often have "uncontrollable" height due to the fact that:
you cannot explicitly dictate vertical dimensions—be it margin, padding, height—on inline elements, resulting in unpredictable dimensions and
the element's vertical height is influenced by line height inherited from the text node.
.layout-toggle {
display: inline-block;
padding: 10px;
border: 1px solid grey;
}
.layout-toggle.layout-active {
background-color: black;
}
.layout-toggle.layout-active svg {
fill: white;
width: 1em;
height: 1em;
}
.layout-toggle .layout-icon {
display: block; /* Use display: block to force proper height */
width: 1em;
height: 1em;
vertical-align: middle;
}
<a href="#">
<div class="layout-toggle">
<svg class="layout-icon" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" viewbox="0 0 17 16" style="enable-background:new 0 0 17 16;" xml:space="preserve">
<g>
<g>
<g id="calendar-view-01">
<g>
<g id="Calender-Layout-Icon_no-border-1">
<path d="M0.3,0h4v4h-4V0z M0.3,6h4v4h-4V6z M0.3,12h4v4h-4V12z M6.3,0h4v4h-4V0z M6.3,6h4v4h-4V6z M6.3,12h4v4h-4
V12z M12.3,0h4v4h-4V0L12.3,0z M12.3,6h4v4h-4V6L12.3,6z M12.3,12h4v4h-4V12L12.3,12z" />
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
</a>

How to set a rotation point on a nested SVG Element

Recently, I decided to experiment and learn about CSS Transforms. Now, I decided to try and make a common mobile button using SVG and a few transforms.
What I'm trying to do is to make the mobile button rotate 90 degrees with a transform origin on the very center of the element.
Here is my code:
.mobileNav {
display: block;
transition: .5s;
}
.mobileNav:hover {
transform: rotate(90deg);
transform-origin: 50% 50%;
/*This is where the problem lies. How do I set the origin to the center of .mobileNav?? */
}
ul {
float: right;
margin: 15px 50px 0px 0px;
}
li {
display: inline-block;
transition: .5s;
}
<ul class="mobileNav">
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
</ul>
GOAL: To set the transform origin to the center of .mobileNav.
PROBLEM: I am unable to achieve this.
BROWSER: My browser is Firefox 44.0.2
ul has defaut padding or margin that needs a reset.
li and svg could be reset to inline-block.
Lets draw a border for debug to see where things stand.
vertical-aign + line-height will help to define an height to ul and will set childs at vertical middle.
body {
margin-top:50px;/* snippet wants this */
}
.mobileNav {
display: block;
transition: .5s;
border: solid;
padding: 0
}
.mobileNav:hover {
transform: rotate(90deg);
}
ul {
float: right;
margin: 15px 50px 0px 0px;
line-height: 1em;
}
li,
svg {
display: inline-block;
vertical-align: middle;
transition: .5s;
}
<ul class="mobileNav">
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />Sorry, your browser does not support inline SVG.
</svg>
</li>
</ul>
Your problem is the default padding. For added effect, you can also set the SVG and li's to not be display inline or inline-block. Then float them so the align vertically. That should make it not as janky.
body {padding: 3em;}
.mobileNav {
display: block;
transition: .5s;
padding: 0;
}
.mobileNav:hover {
transform: rotate(90deg);
transform-origin: 50% 50%;
/*This is where the problem lies. How do I set the origin to the center of .mobileNav?? */
}
ul {
float: right;
margin: 15px 50px 0px 0px;
}
li {
display: inline-block;
transition: .5s;
}
.mobileNav svg, .mobileNav li {
display:block;
float:left;
}
<ul class="mobileNav">
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
<li>
<svg x="0px" y="0px" width="10" height="20">
<circle cx="5" cy="10" r="3" stroke-width="4" fill="#333" />
Sorry, your browser does not support inline SVG.
</svg>
</li>
</ul>