Kevin Patrick
Kevin Patrick

Reputation: 455

How do I center text over a div that dynamically changes width within another div?

I am creating a component in React for an app that displays automation results. I am trying to create a custom progress bar of sorts that displays the percentage of tests that passed. However when I try to center the text it is centered relative to the inner div.

The code for my progress bar is:

import React from 'react';
import classes from './ProgressBar.modules.scss';

const progressBar = props => {
  return (
    <div className={ classes.ProgressBar }>
      <div style={{ width: props.passed }}>
        { props.passed }
      </div>
    </div>
  );
};

My SCSS file looks like:

.ProgressBar {
  width: 125px;
  max-width: 125px;
  background: rgb(255, 97, 97);
  border-radius: 4px;
  height: 40px;
  box-shadow: 0 2px 3px rgb(110, 109, 109);
  overflow: hidden;
  transition: 0.2s ease-in-out;
}

.ProgressBar div {
  background: rgb(98, 167, 98);
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
  height: 40px;
  padding: 8px 1px 9px 5px;
  box-sizing: border-box;
  font-weight: bold;
  color: white;
}

I try to center the text but it only stays centered relative to the green. How do I center this on top of two divs?

Upvotes: 5

Views: 1317

Answers (4)

isacvale
isacvale

Reputation: 647

I'd say that if you want the text and the progress div to be independent, a better structure would be with both text and progress as siblings, like:

<div class="back">
 <div class="front"></div>
 <p>70%</p>
</div>

You can align the text with flexbox:

.back {
  display: flex;
  align-items: center;
  justify-content: center;  
}

And make the progress bar absolute positioned, as to "get out of the way".

.back {
    position: relative;
}

.front {
    position: absolute;
    top: 0;
    left: 0;
}

Of course, since the label is static, it would hide under the positioned progress bar. Then you'd have to positioned him too.

.back > p {
    position: relative;
}

I'm not saying this is the best aproach, but I thought it was worth mentioning because it rearranges the component hierarchy, which I think you should, and it centers the text with flexbox.

.back {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;

    width: 300px;
    height: 60px;
    background: purple;
    border-radius: 8px;
    overflow: hidden;
}

.front {
  position: absolute;
  top: 0;
  left: 0;
  
    width: 70%;
    height: 100%;
    background: orange;
}

p {
  position: relative;
}
<div class="back">
  <div class="front"></div>
  <p>70%</p>
</div>

Upvotes: 1

Emanuele
Emanuele

Reputation: 814

If you want to vertically center the text try to add these lines to your ProgressBar div

display: flex;
flex-direction: column;
justify-content: center;

or if you don't want to use flexbox:

vertical-align: middle;
display: table-cell;

If you want to center the text independently from its parent you can't without another element, for example, a span with an absolute position.

Upvotes: 0

Davi
Davi

Reputation: 4147

Place it in a separate span (or div, p, whatever):

const progressBar = props => {
  return (
    <div className={ classes.ProgressBar }>
      <div style={{ width: props.passed }}></div>
      <span className="label">{props.passed}</span>
    </div>
  );
};

Use position: relative on the outer container:

.ProgressBar {
  position: relative; /* <<< */
  width: 125px;
  max-width: 125px;
  background: rgb(255, 97, 97);
  border-radius: 4px;
  height: 40px;
  box-shadow: 0 2px 3px rgb(110, 109, 109);
  overflow: hidden;
  transition: 0.2s ease-in-out;
}

Then style the span, for example:

.ProgressBar .label {
  position: absolute; /* <<< reason for relative positioning */
  top: 0;
  left: 0;
  width: 100%;
  padding: 5px; /* <<< adjust to your needs */
  text-align: center;
}

Upvotes: 4

Szekelygobe
Szekelygobe

Reputation: 2667

If I understand correctly then you want to center the percentage in the whole progress bar, indifferent of the percentage value.

The simplest answer is to put an empty div with full width, on top of the green div without a background containing the percentage text, and center the text.

Upvotes: 0

Related Questions