Yet again, CSS being problematic again - javascript

So basically this is Day 3 (other days, I pretty much did nothing to complete the game) of making a game from HTML5. So I'm making a moves system right now, and I guess I'm doing well? (mainly because I'm not sure if I provided the user with too many moves...) But the thing about it is that, I'm kind of having ANOTHER styling issue.
As you can see in the image: I've CLEARLY set dimensions up for the headerDisplay class/id, but NO, it goes out of the div's dimensions and even goes on the grid. I'm also aiming for the time and moves text to be stuck right on top of the grid, similarly to how the word bank is stuck to the bottom of the grid.
I was also aiming for a button that says refresh right under the word bank, however no matter what I tried, the button would just be right the score text, which looks like this:
When I am aiming for this:
Code:
<div class="content" id="content">
<div class="headerDisplay" id="headerDisplay">
</div>
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="bottomMenu" id="bottomMenu">
</div>
</div>
::before,
::after {
box-sizing: border-box;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.content {
display: grid;
grid-template-rows: repeat(3, max-content);
margin-block: 1em;
margin-inline: auto;
width: 512px;
}
.bottomMenu {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid #000;
border-radius: 5px;
display: flex;
font-size: 1.6em;
min-height: 3em;
justify-content: space-between;
padding: 0.25em;
}
.wordBank span:nth-child(even) {
align-self: end;
}
.gameArea {
font-size: 0;
justify-self: center;
max-width: 100%;
}
.cell {
border: 1px solid black;
width: 50px;
font-size: 1rem;
height: 50px;
display: inline-block;
}
.headerDisplay {
width: 100%;
height: 76.8px;
text-align: right;
font-size: 1.6em;
}
let score = 0;
const headerDisplay = document.getElementById("headerDisplay")
const bottomMenu = document.getElementById("bottomMenu");
const wordBank = document.getElementById("wordBank")
const gameArea = document.getElementById("gameArea")
const rows = document.getElementsByClassName("gridRow");
const cells = document.getElementsByClassName("cell");
const words = [ // snippet
"ability",
"able",
"about",
"above",
"abroad",
"absence",
"absent",
"absolute",
"accept",
"accident",
"accord",
"account",
"accuse",
"accustom",
"ache",
"across",
"act"
]
let selectedWords = [];
bottomMenu.innerHTML = "<p>Score: " + score;
bottomMenu.innerHTML += "<button>Refresh"
while (selectedWords.length < 5) {
const selectedWord = words[Math.floor(Math.random() * words.length)];
if (selectedWord.length <= 9) {
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
selectedWords.push(selectedWord);
}
}
let longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
let charCount = longestWord.length
var moves = charCount * 5
headerDisplay.innerHTML += "<p>Time: "
headerDisplay.innerHTML += "<p>Moves: " + moves
function makeRows(rowNum) {
for (let r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
}
}
function makeColumns(cellNum) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();

To fix header you need to set its height to fit content, so it will be over your grid even if you change it later:
.headerDisplay {
width: 100%;
height: content-fit; /* previous: 76.8px */
text-align: right;
font-size: 1.6em;
}
And to fix bottom menu you need to add flexbox:
.bottomMenu {
font-size: 24px;
text-align: right;
display: flex; /* new */
flex-direction: row-reverse; /* new */
justify-content: space-between; /* new */
align-items: center; /* new */
}

For the button, you could try this:
button {
position: relative;
right: 400px;
bottom: 50px;
transform: scale(2,2)
}

Related

Card Slider transform translate only working as expected on first click

I am trying to get this card slider to transform cards on each click. Every time the user clicks on any of the cards, the last card in the array goes to the beginning, and all cards are moving as in a carousel, scaling and changing their zIndex. It works perfectly on the first click but then cards start translating differently.
After searching and searching, I read you have to keep track of translations therefore I am using distanceCounter0Elm and distanceCounterElse variables, but it does not seem to work. Also tried to reset all transforms and even a different approach by adding css classes but could not get it to work properly.
Where is my mistake? It might be something very simple but I am not being able to see it. I would really appreciate your help. Many thanks!
<section class="section" id="portfolio">
<h3 class="tituloTrabajos">Nuestros trabajos</h3>
<div class="container" id="grasscoContainer"></div>
</section>
section{
background-color: #021845;
width: 98vw;
height: 180vh;
padding-top: 10vh;
display: flex;
flex-direction: column;
}
.tituloTrabajos{
color: white;
text-align: center;
font-size: 2vw;
margin-bottom: 25vh;
}
.sitesContainer{
display: flex;
justify-content: space-evenly;
align-items: center;
align-content: center;
flex-wrap: wrap;
row-gap: 8vh;
}
.siteDiv{
background-color: #ddf1fc;
}
.sitePic{
width: 38vw;
border-radius: 20px;
}
.container{
position: relative;
height: 150vh;
width: 98vw;
display: flex;
justify-content: center;
overflow: hidden;
}
.eachCard{
width: 38vw;
height: 40vh;
border-radius: 20px;
box-shadow: -5px 0 6px #000, 10px 0 6px #000;
transition: 0.4s ease-out;
position: relative;
border: 5px solid white;
cursor: pointer;
top: 5vh;
}
.eachCard:not(:first-child){
margin-left: -30vw;
}
.originalzIndex2{
z-index: 2;
}
.originalzIndex1{
z-index: 1;
}
.originalScale{
transform: scale(1.2);
}
var grasscoImgs = ["img/grassco2.png", "img/grassco3.png", "img/grassco.png", "img/grassco4.png", "img/grassco6.png"];
var grasscoContainer = document.getElementById("grasscoContainer");
var cards = document.getElementsByClassName("eachCard");
grasscoImgs.forEach(function(image){
var img = document.createElement("img");
img.src = image;
img.classList.add("eachCard");
grasscoContainer.appendChild(img);
img.onclick = slideCards;
});
cards[2].classList.add("originalzIndex2", "originalScale");
cards[3].classList.add("originalzIndex1");
var cardsArr = Array.from(cards);
function slideCards(){
var lastCard = cardsArr.pop();
cardsArr.splice(0, 0, lastCard);
var distanceCounter0Elm = " translate(-32vw)";
var distanceCounterElse = " translate(2vw)";
for (let i = 0; i < cardsArr.length; i++){
if (i == 0){
cardsArr[0].style.transform = distanceCounter0Elm + " scale(0.8)";
cardsArr[0].style.zIndex = "0";
distanceCounter0Elm += " translate(-32vw)";
} else {
cardsArr[1].style.transform = distanceCounterElse + " scale(1)";
cardsArr[2].style.transform = distanceCounterElse + " scale(1.2)";
cardsArr[3].style.transform = distanceCounterElse + " scale(1)";
cardsArr[4].style.transform = distanceCounterElse + " scale(0.8)";
cardsArr[1].style.zIndex = "1";
cardsArr[2].style.zIndex = "2";
cardsArr[3].style.zIndex = "1";
cardsArr[4].style.zIndex = "0";
distanceCounterElse += " translate(2vw)";
};
};
};

Reveal html text letter by letter smoothly on page scroll?

I need help trying to complete a JavaScript effect. I'm looking to accomplish the effect on this site https://www.lucidmotors.com/ - in the third section down on the home page you can see the text scroll/reveal is smooth over the other text.
I found this option on codepen https://codepen.io/Bes7weB/pen/zYKoexK similar to the effect I need, but its a little to choppy I need it to be smoother.
JS
var textWrapper = document.querySelector(".ml3");
textWrapper.innerHTML = textWrapper.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>"
);
var letter = document.querySelectorAll(".letter");
var i = 0;
var currentID = 0;
var slideCount = letter.length;
document.addEventListener("scroll", (e) => {
let scrolled =
document.documentElement.scrollTop /
(document.documentElement.scrollHeight -
document.documentElement.clientHeight);
// var nextID = currentID + 1;
// if (nextID < slideCount) {
// letter[nextID].style.setProperty(
// "--percentage",
// `${scrolled / 1}` * nextID
// );
// }
// currentID = nextID;
letter.forEach(function (l, i) {
// console.log("====",i / letter.length, i, letter.length)
if (i / letter.length < scrolled) {
l.style.setProperty("--percentage", 1);
} else {
l.style.setProperty("--percentage", 0);
}
});
});
CSS
:root {
--percentage: 0;
}
body {
background-color: #000;
margin: 0;
height: 600vh;
}
.ml3 {
position: sticky;
top: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
span {
font-family: Helvetica;
margin: 0;
padding: 0;
font-size: 48px;
color: #fff;
letter-spacing: -0.3px;
}
.ml3 span {
opacity: var(--percentage);
}
HTML
<div class="ml3">
<h1>THIS IS MY TEXT THAT IT'S GOING TO SHOW IN SCROLL</h1>
</div>
Any assistance would be great
This is probably what you're looking for, find it quite interesting and I think my answer can be improved, if you're interested only in the vertical scroll you should check the window.scrollY variable as well.
var textWrapper = document.querySelector(".ml3");
textWrapper.innerHTML = textWrapper.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>"
);
var letter = document.querySelectorAll(".letter");
document.addEventListener("scroll", (e) => {
let scrolled =
document.documentElement.scrollTop /
(document.documentElement.scrollHeight -
document.documentElement.clientHeight) *
letter.length;
letter.forEach(function(l, i) {
if ((scrolled - i) > 1)
l.style.setProperty("--percentage", 1);
else if ((scrolled - i) < 0.2)
l.style.setProperty("--percentage", 0.2);
else
l.style.setProperty("--percentage", (scrolled - i));
});
});
:root {
--percentage: 0.2;
}
body {
background-color: #000;
margin: 0;
height: 600vh;
}
.ml3 {
position: sticky;
top: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
span {
font-family: Helvetica;
margin: 0;
padding: 0;
font-size: 48px;
color: #fff;
letter-spacing: -0.3px;
}
.ml3 span {
opacity: var(--percentage);
}
<div class="ml3">
<h1>THIS IS MY TEXT THAT IT'S GOING TO SHOW IN SCROLL</h1>
</div>

I'm having trouble with the .innerHTML not working properly

I cant get the "if" part to work, thus not outputting the text Test0 or Test1 to my "Test" div after I press either of the links. I have checked for any error messages, which there are none of. I also added the changing color to check if it was the event listeners that were the problem, but that worked fine. So my only problem is that I can't get the text to output.
var testEl = document.querySelector("#test");
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.value === 0) {
testEl.innerHTML = "Test0"
} else if (e.target.value === 1) {
testEl.innerHTML = "Test1"
}
}
.innpakning {
width: 80%;
background-color: #708790;
padding: 10px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.loddrett_meny {
display: flex, block;
flex: 1;
padding-top: 6px;
}
.loddrett_meny a {
display: block;
text-align: center;
padding: 12px;
margin: 4px;
color: white;
font-size: 20px;
text-decoration: none;
}
.loddrett_meny a:hover {
background-color: black;
border-radius: 8px;
transition: 0.75s;
}
.aktiv {
background-color: #3cb500;
}
.ikke_aktiv {
background-color: #555;
}
.innhold,
#test {
flex: 6;
height: auto;
background-color: #a6d4a3;
padding-left: 2px;
border-radius: 2px;
margin: 10px;
margin-right: 0px;
font-size: 20px;
}
<div class="innpakning">
<div class="loddrett_meny">
<a class="aktiv" value="0">Kapittel 20</a>
<a class="ikke_aktiv" value="1">Kapittel 20.1</a>
</div>
<div id="test"></div>
</div>
You need to use quotes around values or convert them to Number
if(e.target.value === "0"){
testEl.innerHTML = "Test0"
}else if(Number(e.target.value) === 1){
testEl.innerHTML = "Test1"
}
Adding on what Abdulah Proho said: You can't add the value attribute to a tags, so it's discarded and e.target.value. You may use data attributes for this:
var testEl = document.querySelector("#test");
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.dataset.value === "0") {
testEl.innerHTML = "Test0"
} else if (e.target.dataset.value === "1") {
testEl.innerHTML = "Test1"
}
}
.innpakning {
width: 80%;
background-color: #708790;
padding: 10px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.loddrett_meny {
display: flex, block;
flex: 1;
padding-top: 6px;
}
.loddrett_meny a {
display: block;
text-align: center;
padding: 12px;
margin: 4px;
color: white;
font-size: 20px;
text-decoration: none;
}
.loddrett_meny a:hover {
background-color: black;
border-radius: 8px;
transition: 0.75s;
}
.aktiv {
background-color: #3cb500;
}
.ikke_aktiv {
background-color: #555;
}
.innhold,
#test {
flex: 6;
height: auto;
background-color: #a6d4a3;
padding-left: 2px;
border-radius: 2px;
margin: 10px;
margin-right: 0px;
font-size: 20px;
}
<div class="innpakning">
<div class="loddrett_meny">
<a class="aktiv" data-value="0">Kapittel 20</a>
<a class="ikke_aktiv" data-value="1">Kapittel 20.1</a>
</div>
<div id="test"></div>
</div>
e.target.value is undefined. Due to anchor tags usually not having value attribute. The 'a' elements don't have the data prototype for value.
You should try getting the value using:
e.target.getAttribute('value')
Also while comparing try using:
e.target.getAttribute('value') === '0'
Given the value you get from getAttribute function is a string the value getting compared with should also be a string.
The following works I have tested it as a snippet. Trying copying this entirely and replace it with your js. you need to use the getAttribute method to get the value.
var testEl = document.getElementById("test");;
var menyEl = document.querySelectorAll("a");
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].addEventListener("click", byttInfo);
}
function byttInfo(e) {
if (e.target.className === "ikke_aktiv") {
for (var i = 0; i < menyEl.length; i++) {
menyEl[i].className = "ikke_aktiv";
}
e.target.className = "aktiv"
}
if (e.target.getAttribute("value") === "0"){
testEl.innerText = "Test0"
} else if (e.target.getAttribute("value") === "1") {
testEl.innerText = "Test1"
}
}

modifying this beautiful number ticker

Here is a beautiful Number Ticker. the whole day I was wondering and trying to modify the code to make it as I want but no success till now!
if you work with numbers with two or more digits then the code creates separate black squares to hold each digit ( run code snippet to have a look ), but I want only a single square as the container to hold multiple digit numbers. So if we have a two-digit number like 10 the Number Ticker should be something like this:
And the next move should look like :
I don't want those parallel animations that move two digits like this (Only the single animation is required not both):
Here is the code:
let counters = document.getElementsByClassName('number-ticker');
let defaultDigitNode = document.createElement('div');
defaultDigitNode.classList.add('digit');
for (let i = 0; i < 11; i++) {
defaultDigitNode.innerHTML += i + '<br>';
}
[].forEach.call(counters, function(counter) {
let currentValue = 10;
let digits = [];
generateDigits(currentValue.toString().length);
setValue(currentValue);
setTimeout(function() {
setValue(8);
}, 2000);
setTimeout(function() {
setValue(7);
}, 5000);
function setValue(number) {
let s = number.toString().split('').reverse().join('');
let l = s.length;
if (l > digits.length) {
generateDigits(l - digits.length);
}
for (let i = 0; i < digits.length; i++) {
setDigit(i, s[i] || 0);
}
}
function setDigit(digitIndex, number) {
digits[digitIndex].style.marginTop = '-' + number + 'em';
}
function generateDigits(amount) {
for (let i = 0; i < amount; i++) {
let d = defaultDigitNode.cloneNode(true);
counter.appendChild(d);
digits.unshift(d);
}
}
});
:root {
background-color: #555;
color: white;
font-size: 25vh;
font-family: Roboto Light;
}
body,
html {
margin: 0;
height: 100%;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.number-ticker {
overflow: hidden;
height: 1em;
background-color: #333;
box-shadow: 0 0 0.05em black inset;
}
.number-ticker .digit {
float: left;
line-height: 1;
transition: margin-top 1.75s ease;
border-right: 1px solid #555;
padding: 0 0.075em;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Number Ticker</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="number-ticker.css">
</head>
<body>
<div class="container">
<div class="number-ticker" data-value="0"></div>
</div>
<script src="number-ticker.js"></script>
</body>
</html>
Your css has this
.number-ticker .digit {
float: left;
line-height: 1;
transition: margin-top 1.75s ease;
border-right: 1px solid #555;
padding: 0 0.075em;
}
You need to change it to this
.number-ticker .digit {
float: left;
line-height: 1;
transition: margin-top 1.75s ease;
padding: 0 0.075em;
text-align: center;
}
If you remove border-right: 1px solid #555 you will have it look like 1 box.
Also I added text-align: center to center the numbers.
Hope this solves your problem :)
I think the main issue in your code is the digits variable. It creates an array of HTML elements that holds two blocks.
Also, for this line:
let s = number.toString().split('').reverse().join('');
Why do you need to convert number to a string. You can just pass it as is. Once you add to a string using + it will be converted.
I made few changes to your code and commented out the non-relevant part. Please see below:
let counters = document.getElementsByClassName('number-ticker');
let defaultDigitNode = document.createElement('div');
defaultDigitNode.classList.add('digit');
for (let i = 0; i < 11; i++) {
defaultDigitNode.innerHTML += i + '<br>';
}
[].forEach.call(counters, function(counter) {
// let currentValue = 10;
// let digits = [];
let currentValue = counter.getAttribute("data-value");
let digit = null;
generateDigits(currentValue.toString().length);
setValue(currentValue);
setTimeout(function() {
setValue(8);
}, 2000);
setTimeout(function() {
setValue(7);
}, 5000);
setTimeout(function() {
setValue(10);
}, 8000);
function setValue(number) {
// let s = number.toString().split('').reverse().join('');
// let l = s.length;
/*if (l > digits.length) {
generateDigits(l - digits.length);
}*/
/*for (let i = 0; i < digits.length; i++) {
setDigit(i, s[i] || 0);
}*/
digit.style.marginTop = '-' + number + 'em';
}
/*function setDigit(digitIndex, number) {
console.log(number);
digits[digitIndex].style.marginTop = '-' + number + 'em';
}*/
function generateDigits(amount) {
// console.log("generat", amount);
// for (let i = 0; i < amount; i++) {
let d = defaultDigitNode.cloneNode(true);
digit = counter.appendChild(d);
// digits.unshift(d);
// }
}
});
:root {
background-color: #555;
color: white;
font-size: 25vh;
font-family: Roboto Light;
}
body,
html {
margin: 0;
height: 100%;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.number-ticker {
overflow: hidden;
height: 1em;
background-color: #333;
box-shadow: 0 0 0.05em black inset;
}
.number-ticker .digit {
float: left;
line-height: 1;
transition: margin-top 1.75s ease;
border-right: 1px solid #555;
padding: 0 0.075em;
text-align: center;
}
<div class="container">
<div class="number-ticker" data-value="0"></div>
</div>
Your final JS could be like this:
let counters = document.getElementsByClassName('number-ticker');
let defaultDigitNode = document.createElement('div');
defaultDigitNode.classList.add('digit');
for (let i = 0; i < 11; i++) {
defaultDigitNode.innerHTML += i + '<br>';
}
[].forEach.call(counters, function(counter) {
let currentValue = counter.getAttribute("data-value");
let d = defaultDigitNode.cloneNode(true);
let digit = counter.appendChild(d);
setValue(currentValue);
function setValue(number) {
digit.style.marginTop = '-' + number + 'em';
}
});

customize the look of dynamically created DIVs

The script creates a random number of divs (in range 20-40) and puts some text in every single div. The script calculates the width of divs so that they fit in a single row. The height should be equal to the width - every div must be a square. Here's the code:
var quantity = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
for (var i = 0; i < quantity; i++) {
var elem = document.createElement("div");
elem.className = "part";
elem.id = 'p' + i;
document.getElementById("scale").appendChild(elem);
}
var parts = document.getElementsByClassName("part");
for (var i = 0; i < parts.length; i++) {
parts[i].style.fontSize = (500 / quantity) + 'px';
parts[i].style.lineHeight = (460 / quantity) + 'px';
parts[i].textContent = ("block #" + (i + 1));
}
for (var i = 0; i < parts.length; i++) {
parts[i].style.height = parts[i].style.width;
}
let text = document.getElementById('txt');
text.textContent = 'BLOCKS: ' + quantity;
body {
margin: 0;
}
#scale {
position: absolute;
display: table;
width: 100%;
top: 50%;
transform: translateY(-100%);
table-layout: fixed;
border-spacing: 1px;
}
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
}
#txt {
position: absolute;
top: 50%;
left: 50%;
margin-top: 20px;
transform: translateX(-50%);
font-size: 18px;
font-family: 'Arial', sans-serif;
}
<div id="scale"> </div>
<div id='txt'> </div>
The first problem is the divs are not always square. The second problem is I can't properly set the font size depending on a div size, so text fits a div. I think that's the worst solution
parts[i].style.fontSize = (500 / quantity) + 'px';
parts[i].style.lineHeight = (460 / quantity) + 'px';
There were two problems with the code:
To get element with use .clientWidth because style.width can be accessed when you have set that but in your code, I couldn't see you are doing so.
Second use font size in per cent, I don't think line-height is required. To make it centre use CSS as in example follows.
Use following:
var quantity = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
for (var i = 0; i < quantity; i++) {
var elem = document.createElement("div");
elem.className = "part";
elem.id = 'p' + i;
document.getElementById("scale").appendChild(elem);
}
var parts = document.getElementsByClassName("part");
for (var i = 0; i < parts.length; i++) {
parts[i].style.fontSize = (500 / quantity) + '%';
parts[i].style.lineHeight = (460 / quantity) + '%';
parts[i].textContent = ("block #" + (i + 1));
}
for (var i = 0; i < parts.length; i++) {
parts[i].style.height = parts[i].clientWidth + "px";
}
let text = document.getElementById('txt');
text.textContent = 'BLOCKS: ' + quantity;
body {
margin: 0;
}
#scale {
position: absolute;
display: table;
width: 100%;
top: 50%;
transform: translateY(-100%);
table-layout: fixed;
border-spacing: 1px;
}
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
vertical-align: middle;
text-align: center;
}
#txt {
position: absolute;
top: 50%;
left: 50%;
margin-top: 20px;
transform: translateX(-50%);
font-size: 18px;
font-family: 'Arial', sans-serif;
}
<div id="scale"> </div>
<div id='txt'> </div>
Or if you don't want to use your text font to be reduced like this use following:
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
vertical-align: middle;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}

Categories