Why does setting view width and height not suffice to enforce full browser window rendering of SVG element?

Viewed 82

PROBLEM

I have the following html, in which I am attempting to draw an SVG viewport containing a line the size of my browser window:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <svg xmlns="http://www.w3.org/2000/svg" 
    style="outline: 5px solid red" width="100vw" height="100vh">
        <line x1="0" y1="75%" x2="250" y2="50" stroke="black"/>
    </svg>
   </body>
</html>

However, when I render the html the viewport appears to be larger than my browser window as I must scroll to see the full extent of my SVG viewport as shown below:

enter image description here

GOAL

My goal is to get the viewport to be exactly the size of my browser window as follows:

enter image description here

ATTEMPTING USE OF BORDER-BOX

The border-box redefines the width to include padding, border and margins. If the width and height is set to 100vw and 100vh under border-box behavior, that should include all padding, border and margins in the full browser window. However this does not seem to work:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      svg {
        box-sizing: border-box;
        outline: 5px solid red;
        width: 100vw;
        height: 100vh;
      }
    </style>
  </head>
  <body>
      <svg xmlns="http://www.w3.org/2000/svg">
        <line x1="0" y1="75%" x2="250" y2="50" stroke="black" />
      </svg>
  </body>
</html>

ADDING BLOCK ELEMENT BEHAVIOR

According to one of the answers below svg's act as inline elements by default. That's fine, but then simply including display: block in the css should fix the issue, however this doesn't work:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
            svg {
            box-sizing: border-box;
            border: 5px solid red;
            width: 100vw;
            height: 100vh;
            display: block;
            }
        </style>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg">
            <line x1="0" y1="75%" x2="250" y2="50" stroke="black" />
        </svg>
    </body>
</html>

OBJECTIONS TO SOME ANSWERS

  1. I don't see why using % units is imperative here. % simply provides a relative length with respect to the parent element, which in this case is body. vw and vh provide lengths relative to the viewport window as explained in this link. In this particular application I care more about the viewport window rather than the body element itself...
  2. I don't see why setting the margin of the body element to 0 is necessary here. The body element contains the svg block, but since the svg block is defined in terms of view heights and widths that should result in independent width and height behavior from the body element.
3 Answers

SVG elements are displayed inline by default.

add in your css, and check result

svg {
  box-sizing: border-box;
  border: 5px solid red;
  width: calc(100vw - 10px - 8px);
  height: calc(100vh - 10px - 8px);
  display: block;
}

source

Take away margin for the body tag.

body {
    margin: 0;
}

Replace the type of display of the svg border with a border so as not to violate the nominal size of svg. Set the width to width: 100%. And make the svg blocky by setting display: block.

svg {
    display: block;
    border: 5px solid red;
    width: 100%;
    ...
}

body {
    margin: 0;
}

svg {
    display: block;
    box-sizing: border-box;
    border: 5px solid red;
    width: 100%;
    height: 100vh;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg">
            <line x1="0" y1="75%" x2="250" y2="50" stroke="black" />
        </svg>
    </body>
</html>

To get the result as in your screenshot, set the height using the calc() function to subtract the upper - 8px and lower - 8px margins of the body tag equal to 16 px:

height: calc(100vh - 16px);

svg {
    display: block;
    box-sizing: border-box;
    border: 5px solid red;
    width: 100%;
    height: calc(100vh - 16px);
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg">
            <line x1="0" y1="75%" x2="250" y2="50" stroke="black" />
        </svg>
    </body>
</html>

Google Chrome's developer tools came in extremely handy here. Highlighting the body and svg elements in the DOM and inspecting the items in the browser showed the following:

  • The body element has a default margin >0, but the default border and padding appears to equal 0.
  • The svg element has a default margin and padding equal to 0.
  • The default border for the svg element is nonzero here, hence the need for border-box behavior when assigning width and height of the viewport

The browser was basically appending a nonzero default margin from the body element to the 100 view heights and view widths that I was assigning to the svg element. So it makes sense that, with my initial code, a scrollbar was appearing.

Forcing a zero margin on the body element removes all extraneous white space around my SVG content, and as @s.kuznetsov and @Zia Ur Rehman indicated, this results in the desired output. This is the code I ended up with:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
            body{
                margin:0;
            }
            svg {
            box-sizing: border-box;
            border: 5px solid red;
            width: 100vw;
            height: 100vh;
            display: block;
            }
        </style>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg">
            <line x1="0" y1="75%" x2="250" y2="50" stroke="black" />
        </svg>
    </body>
</html>

I believe this answer clarifies why I was getting a scrollbar in the first place, contrarily to the other answers. However, I will accept one of the other answers as a courtesy and because they allowed me to understand what was going on in my code.

Related