Is there a way to stop this outline in firefox?
#blob { background: red; width: 500px; height: 500px; clip-path: url(#myClip); transform: rotate(20deg);}
<div id="blob"></div>
<svg>
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1"></path>
<clipPath id="myClip"><use href="#path-1"></use></clipPath>
</defs>
</svg>
This renders correctly in other browsers, just need some work around for this firefox bug
same outline appears using either clip-path or mask
As a workaround you could rotate the clipPath instead:
#blob {
background: red;
width: 500px;
height: 500px;
clip-path: url(#myClip);
}
<div id="blob"></div>
<svg viewBox="0 0 397 409">
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1" />
<clipPath id="myClip" transform="rotate(20)" transform-origin="center">
<use href="#path-1"></use>
</clipPath>
</defs>
</svg>
So I have been asked to make a section number that is constructed as a non-filled circle with a 2px border containing a number. The range of the numbers is 1 to 999.
As you can see from the example below, it looks pleasing at one & two digit section numbers, but when we hit three digits the number is clipped.
My thinking is that there needs to be a process where the text is drawn, measured, then scaled to fit into the target space inside the circle, where the target space is effectively a square rect 60% of the diameter of the circle.
However, no JS is allowed in the solution.
I thought it might be possible using SVG and its scaling capabilities via the 'preserveAspectRatio' parameter. However the image above is a screen grab of my SVG results. Working snippet below.
My intention with the code was to have the inner SVG containing the text resize proportionally so that it would fit the width of the parent, with the height set to auto so that it would change in proportion.
Can anyone tell me where I am going wrong?
PS. I am using Chrome on PC to test.
Note: In the following snippet the output looks like the image, so 8, then 88, then 888. The markup is the same for each case - only the text content changes.
body {
padding: 20px;
overflow: hidden;
background-color: #f0f0f0;
}
.counterDiv {
width: 44px;
max-width: 44px;
min-width: 44px;
height: 44px;
max-height: 44px;
min-height: 44px;
margin: 0;
padding: 0;
}
svg {
width: 100%;
height: 100%;
}
text {
font: normal normal 18pt Helvetica, Arial, Verdana;
}
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">8</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">88</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em">888</text>
</svg>
</g>
</svg>
</div>
A posible solution would be using textLength and lengthAdjust. The lengthAdjust attribute controls how the text is stretched into the length defined by the textLength attribute. One inconvinient would be that the 1 digit numbers would be stretched.
An alternative solution would be using a smaller font size.
Also you may want to use javascript to target only the 3 digit text elements.
body {
padding: 20px;
overflow: hidden;
background-color: #f0f0f0;
}
.counterDiv {
width: 44px;
max-width: 44px;
min-width: 44px;
height: 44px;
max-height: 44px;
min-height: 44px;
margin: 0;
padding: 0;
}
svg {
width: 100%;
height: 100%;
}
text {
font: normal normal 18pt Helvetica, Arial, Verdana;
}
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">8</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">88</text>
</svg>
</g>
</svg>
</div>
<div class='counterDiv' style='position: relative;'>
<svg viewbox="0 0 44 44">
<g>
<circle cx="22" cy="22" r="20" stroke="#cd1041" stroke-width="2px" fill-opacity="0" />
<svg viewBox="0 0 100 auto" x="20%" width="60%" preserveAspectRatio="xMidYMid meet">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle" fill="#cd1041" dy=".1em" textLength="25" lengthAdjust="spacingAndGlyphs">888</text>
</svg>
</g>
</svg>
</div>
Not for OP,
but for all those SVG loving people who have an inner-guide (or sensible boss)
that tells them: "JavaScript is fine, when applied with common sense"
customElements.define("svg-counter", class extends HTMLElement {
connectedCallback() {
this.render();
}
render(
val = this.getAttribute("value") || "888",
color = "green",
circlestrokewidth = 4,
circlestroke = "red",
circlefill = "none"
){
let id = "P" + (new Date() / 1); // uniqueid
let singleDigit = val.length == 1;
this.innerHTML = `
<svg viewbox="0 0 100 100">
<circle cx="50" cy="50" r="${50-circlestrokewidth}" stroke="${circlestroke}"
fill="${circlefill}" stroke-width="${circlestrokewidth}"/>
<path id="${id}" pathLength="100" d="M0 60H100" stroke="none"/>
<text transform="scale(${singleDigit?1:.7})" transform-origin="50 50">
<textPath href="#${id}" method="stretch"
textlength="100" lengthAdjust="${singleDigit?"":"spacingAndGlyphs"}"
startoffset="50" text-anchor="middle" dominant-baseline="middle"
font-family="Helvetica"
fill="${color}" font-size="${100}px">${val}</textPath>
</text>
</svg>`;
}
});
svg {
width: 20%;
}
<svg-counter value="8"></svg-counter>
<svg-counter value="88"></svg-counter>
<svg-counter value="888"></svg-counter>
<svg-counter value="8888"></svg-counter>
Alas FireFox has some issues, slight tweaked version to make it work in FireFox:
Alas I have a boss who says "We don't care about FireFox customers"
customElements.define("svg-counter", class extends HTMLElement {
connectedCallback() {
this.render();
}
render(
val = this.getAttribute("value") || "888",
color = "green",
circlestrokewidth = 4,
circlestroke = "red",
circlefill = "none"
){
let id = "P" + (new Date() / 1) + val.length; // uniqueid
let singleDigit = val.length == 1;
this.innerHTML = `
<svg viewbox="0 0 100 100">
<circle cx="50" cy="50" r="${50-circlestrokewidth}" stroke="${circlestroke}"
fill="${circlefill}" stroke-width="${circlestrokewidth}"/>
<path id="${id}" pathLength="100" d="M0 55H100" stroke="blue"/>
<text transform="scale(${[0,1.7,1.2,.9,.7][val.length]})" transform-origin="50 50">
<textPath href="#${id}" method="stretch"
textlength="100" lengthAdjust="${singleDigit?"":"spacingAndGlyphs"}"
startoffset="50" text-anchor="middle" dominant-baseline="middle"
font-family="Helvetica"
fill="${color}" font-size="50px">${val}</textPath>
</text>
</svg>`;
}
});
svg {
width: 20%;
}
<svg-counter value="8"></svg-counter>
<svg-counter value="88"></svg-counter>
<svg-counter value="888"></svg-counter>
<svg-counter value="8888"></svg-counter>
Not sure this is possible, so I have a back-up plan (use a background image and :after to mask one of 3x transarent PNGs with the border in the image and use nth-child to change them).
Here's what I'm trying to accomplish. I know clip-path will give me the image mask, but I need the curved edges and the border color, too. Which I don't think is possible in pure CSS.
<!DOCTYPE html>
<html>
<style>
img {
max-width: 100%;
display: block;
}
.container {
width: 300px;
height: 300px;
margin: 1em auto;
}
.frame-border {
stroke: #10c020;
stroke-width: 4;
}
</style>
<body>
<div class="container">
<svg viewBox="-10 -10 120 120">
<defs>
<mask id="mask">
<rect fill="#000000" x="0" y="0" width="300" height="300"></rect>
<path id="Path_611" data-name="Path 611" d="M1,38a12.225,12.225,0,0,1,2.558-3.025L41.351,13.462A21.12,21.12,0,0,1,46.733,12.4a14.319,14.319,0,0,1,4.81.765L89.2,34.814A7.333,7.333,0,0,1,92,37a7.273,7.273,0,0,1,1,3.4v45.3A6.741,6.741,0,0,1,92,89a12.9,12.9,0,0,1-3.015,2.945L50.42,110.628a8.953,8.953,0,0,1-3.688.786,13.383,13.383,0,0,1-4.153-.992L4.2,92.012A12.105,12.105,0,0,1,1,89a7.112,7.112,0,0,1-1-3.581V41.534A9.569,9.569,0,0,1,1,38Z" transform="translate(1.502 -10.892)" fill="#FFFFFF"/>
</mask>
</defs>
<image mask="url(#mask)"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://randomuser.me/api/portraits/women/47.jpg" width="100" height="100">
</image>
<g class="frame-border" fill="none">
<path id="Path_611" data-name="Path 611" d="M1,38a12.225,12.225,0,0,1,2.558-3.025L41.351,13.462A21.12,21.12,0,0,1,46.733,12.4a14.319,14.319,0,0,1,4.81.765L89.2,34.814A7.333,7.333,0,0,1,92,37a7.273,7.273,0,0,1,1,3.4v45.3A6.741,6.741,0,0,1,92,89a12.9,12.9,0,0,1-3.015,2.945L50.42,110.628a8.953,8.953,0,0,1-3.688.786,13.383,13.383,0,0,1-4.153-.992L4.2,92.012A12.105,12.105,0,0,1,1,89a7.112,7.112,0,0,1-1-3.581V41.534A9.569,9.569,0,0,1,1,38Z" transform="translate(1.502 -10.892)" stroke-linecap="round" />
</g>
</svg>
</div>
</body>
</html>
I have the following SVG:
body {
background-color: #dad9c7;
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Which looks like this:
How can I do the following?
Keep heights of colored strips the same when scaling the window (not scale).
Stretch colored strips horizontally to the edges of the viewport on either side left and right.
Stretch the top-most rectangle to the top of the screen so the upper third of the viewport is orange and stretch the bottom-most rectangle to the bottom of the viewport so that the lower third of the viewport is purple.
Always keep the "square" centered vertically which already works with CSS, but however the SVG is manipulated to solve would have to keep this into account.
Here is an example of how this would look: As the window gets taller, the colored rectangles will stay in the middle, but the top orange and bottom purple would be cut off based on the height of the viewport.
How can I do the following?
Keep heights of colored strips the same when scaling the window (not scale).
You are already doing this by setting height to 400px.
Stretch colored strips horizontally to the edges of the viewport on either side left and right.
Set preserveAspectRatio="none" on the SVG. See below.
body {
background-color: #dad9c7;
}
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<svg viewBox="0 0 1000 1000" preserveAspectRatio="none">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Stretch the top-most rectangle to the top of the screen so the upper third of the viewport is orange and stretch the bottom-most rectangle to the bottom of the viewport so that the lower third of the viewport is purple.
You cannot automatically stretch the rectangle itself with CSS. But one way you could do it is to use pseudo elements to colour the top and bottom halves of the parent element with matching colours.
body {
background-color: #dad9c7;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 0;
margin: 0;
}
svg {
position: absolute;
width: 100%;
height: 400px;
margin: 0 auto;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
body::before {
content: "";
display: block;
position: absolute;
width: 100%;
top: 0;
bottom: 50%;
background-color: #d5835b;
}
body::after {
content: "";
display: block;
position: absolute;
width: 100%;
top: 50%;
bottom: 0;
background-color: #313d53;
z-index: -1;
}
<svg viewBox="0 0 1000 1000" preserveAspectRatio="none">
<g>
<rect width="1000" height="151" x="0" y="0" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="176" x="0" y="825" fill="#313d53" />
</g>
</svg>
Always keep the "square" centered vertically which already works with CSS, but however the SVG is manipulated to solve would have to keep this into account.
N/A here.
Alternate pure-SVG solution
There is also a pure SVG solution using nested <svg> elements. The only CSS we are using is just to ensure the SVG occupies the full size of the page.
It works by making the top and bottom rectangles extend outside the viewBox by an extra 1000 pixels. To make sure they are visible, we set overflow="visible". 1000 is an arbitrary value. If you want to support screens > 2400 pixels high, then you could choose a larger value.
The inner SVG gets centred vertically using a combination of a y offset and a transform that shifts it up by 200px. This is equivalent to the common top: 50%; transform: translate(0,-50%)" trick to vertically centre CSS block elements.
body {
background-color: #dad9c7;
padding: 0;
margin: 0;
}
#mysvg {
position: absolute;
display: block;
width: 100%;
height: 100%;
}
<svg id="mysvg">
<g transform="translate(0, -200)">
<svg width="100%" height="400px"
y="50%" transform="translate(0, -200)"
viewBox="0 0 1000 1000" preserveAspectRatio="none"
overflow="visible">
<g>
<rect width="1000" height="1151" x="0" y="-1000" fill="#d5835b" />
<rect width="1000" height="151" x="0" y="150" fill="#d47966" />
<rect width="1000" height="126" x="0" y="300" fill="#b66961" />
<rect width="1000" height="101" x="0" y="425" fill="#d17385" />
<rect width="1000" height="101" x="0" y="525" fill="#aa617c" />
<rect width="1000" height="101" x="0" y="625" fill="#a36d8f" />
<rect width="1000" height="101" x="0" y="725" fill="#736d87" />
<rect width="1000" height="1176" x="0" y="825" fill="#313d53" />
</g>
</svg>
</g>
</svg>
You cannot use media queries or css styling for that since a svg does not support that. If you really need to that with an SVG, you will need some Javascript to accomplish your desired effect. In your case, I guess it is simpler to create that using html and css with some media queries.
The only thing you can control when scaling/displaying a SVG is the preserveAspectRatio attribute. A detailed description can be found here.