Ryan
Ryan

Reputation: 195

Vertically centering part of svg content

I've been trying to center a collection of svg paths/text vertically in CSS / JS for quite a while with no luck. None of the solutions I've found here have worked so far. I have multiple < text > , < circle >, < rect >, although I don't think the type of content really matters.

The height is variable, so I have thought of 2 methods: 1) Transform via 50%. This is not working because you cannot transform a sub-set of content from a svg, from what I have found so far. The < g > tag was promising but I had no luck.

2) My second idea was to adjust the mask down via javascript once content is loaded. This, likewise, is not working.

All code is on code-pen and copied here as well: https://codepen.io/anon/pen/MmdWXB

HTML:

<div class="mask_group" id="mask_container">
<div class="text">
  <svg>
   <defs>
     <mask id="mask" x="0" y="0" width="100%" height="100%" >
       <rect class="cutout label" x="0" y="0" width="100%" height="100%"/>
       <text class="label normal_font_weight" y="1em" dy="0em" x="50%">A</text>
       <text class="label normal_font_weight" y="3em" dy="0em" x="50%">B</text>
       <line class="label" x1="47%" y1="4.6em" x2="53%" y2="4.6em" style="stroke:rgb(255,0,0);stroke-width:1.5" />
       <text class="label" y="7em" dy="0em" x="50%">C</text>
       <text class="label" y="9em" id="final_text" dy="0em" x="50%">D</text>
        </mask>
    </defs>
    <rect id="base" x="0" y="0" width="100%" height="100%"/>
  </svg>
</div>
</div>

<div style="background-color:blue; width: 100%; height: 100%">
</div>

CSS:

html,body {
height: 100%;
}

.text {
  position: relative;
   /*top: 0;
   left: 0;*/
   width: 100%;
   height: 100%;
   margin-left: 0%;
   /*z-index: 11; */
 }

 .mask_group {
   position: fixed;
   width: 100%;
   height: 100%;
   z-index: 10; 

 }

 svg {
   position: absolute;
   width: 100%;
   height: inherit;
 }
 svg text {
   text-anchor: middle;
 }
 .cutout {
   fill: white;
 }

 svg #base {
   fill: #051E2A; /*#1F5773;*/
   -webkit-mask: url(#mask);
           mask: url(#mask);
 }


 /*Unused*/
 .vert_center {
   position: relative;
   margin-top: 50%;
   transform: translateY(-50%);

 }

JS:

function body_loaded() {

  var final_text = document.getElementById("final_text");
  var position = final_text.getBoundingClientRect();
  var bottom = position.bottom;

  var mask_container = document.getElementById("mask_container");
  var mask_position = mask_container.getBoundingClientRect();
  var mask_height = mask_position.height;

  var origin_y = (mask_height - bottom) / 2;
  alert(origin_y);

  var mask = document.getElementById("mask"); 
  mask.style.y = origin_y;
}

Thanks ahead of time!

Upvotes: 0

Views: 355

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101956

I'm not sure what you are attempting to do with the <mask>, so I am going to ignore it for now.

To vertically centre the SVG, just give it a fixed height and use the standard translate(-50%) trick. The only wrinkle is that you can't put the CSS transform on the <svg> element because transform has a different behavior in SVGs than it does in CSS. SVG transforms pre-date CSS transforms. So you just need to wrap the SVG in an HTML container and apply the transform to that instead.

I've set the height of the <svg> to 10em. Obviously you'll need to adjust that if you have more text. You could do that with JS using

svgElem.setAttribute("height", "10em");

But take it out of the CSS first obviously :)

html,body {
height: 100%;
}

.svg-wrapper {
  position: absolute;
  width: 100%;
  top: 50%;
  transform: translate(0, -50%);
}

.mask_group {
  position: fixed;
  width: 100%;
  height: 100%;
  z-index: 10; 
}

svg {
  width: 100%;
  height: 10em;
  fill: blue;  /* default fill colour for contents */
}
svg text {
  text-anchor: middle;
}

svg #base {
  fill: #051E2A; /*#1F5773;*/
}
<div class="mask_group" id="mask_container">
  <div class="svg-wrapper">
    <svg>
      <rect id="base" x="0" y="0" width="100%" height="100%"/>
      <text class="label normal_font_weight" y="1em" dy="0em" x="50%">A</text>
      <text class="label normal_font_weight" y="3em" dy="0em" x="50%">B</text>
      <line class="label" x1="47%" y1="4.6em" x2="53%" y2="4.6em" style="stroke:rgb(255,0,0);stroke-width:1.5" />
      <text class="label" y="7em" dy="0em" x="50%">C</text>
      <text class="label" y="9em" id="final_text" dy="0em" x="50%">D</text>
    </svg>
  </div>
</div>

<div style="background-color:blue; width: 100%; height: 100%">
</div>

Upvotes: 1

Related Questions