Muss <span id="pgInfoBattery"/> denn ein Kind von <div id="pgBattery"/>
sein? Als Sibling hättest Du das Problem nicht (und es erschiene mir
auch logischer).
Aber es geht auch so.
Ich ignoriere mal das Bootstrap-Gedöns, denn erstens mag ich Bootstrap
nicht und zweitens ist es leichter, etwas zu erklären, wenn nicht im
Hintergrund hunderttausend weitere Regeln mitmischen.
<!DOCTYPE html
<html>
<style>
.progress-bar-vertical {
border: 1px solid blue;
height: 200px;
}
#pgInfoBattery {
position: absolute;
top: calc(100px - 0.5em);
}
</style>
<div class="col-4 align-items-center justify-content-center">
<div class="progress progress-bar-vertical" style="width: 100%; position: relative;">
<div id="pgBattery" class="progress-bar progress-bar-striped "
role="progressbar" aria-valuemin="0"
aria-valuemax="100"
style="height: 30%; background-color: lightgreen;
color: black; " >
<span id="pgInfoBattery" >XXX</span>
</div>
</div>
</div>
</html>
Das äußere <div/> hat bereits »position: relative«, etabliert also einen
neuen Layout-Kontext. Alle Positionsangaben von Nachfahren-Elementen
orientieren sich also an dem. Daher kann man #pgInfoBattery mit
»position: absolute« absolut innerhalb des <div/>s positionieren. Hier
berechne ich den für eine Zentrierung notwendigen Abstand zum oberen
Rand (unter der Annahme, dass die Höhe des Elements bekannt ist).
hp