Adding non-centered text shifts centered elements [duplicate] - javascript

This question already has answers here:
How to prevent scrollbar from repositioning web page?
(26 answers)
Closed 4 years ago.
After putting a centered header, I add a non-centered output with JS. After the output is produced, the header shifts a bit left. What can be done to tackle this problem?
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
.header {
background-color: lightgray;
border: none;
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button style="font-size:20pt;height:35pt" onclick="spit()">
Press me!
</button>
<p id="output">
</p>

One crazy solution might be to set you body height to the view port height, that way you start off with a scroll, avoiding the shift when the button gets pressed.
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
body {
min-height: 100vh;
}
.header {
background-color: lightgray;
border: none;
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button style="font-size:20pt;height:35pt" onclick="spit()">
Press me!
</button>
<p id="output">
</p>

I added a universal { margin:0; padding:0;} to your css code. The code did seem to be centered but I think the margin of -50 (that's being created by the auto margin ) is throwing off the look.
let output = [];
function spit() {
for (let i = 0; i < 100; i++) {
output.push(i);
}
document.getElementById("output").innerHTML =
output.join("<br>");
}
* {
margin: 0px; padding:0px;
}
button {
/*margin-left:15px;*/
margin-top:7px;
font-size: 20pt;
height: 35pt;
}
.header {
background-color: lightgray;
/* border: 15px solid white;*/ /*use the commented props if you still want the "indented" effect" */
color: black;
padding: 17px 25px;
display: block;
text-align: center;
font-size: 36px;
width: 100%;
margin-right:auto;
margin-left:auto;
}
<h2 id="dictName" class="header">
Testing Page
</h2>
<button onclick="spit()">
Press me!
</button>
<p id="output">
</p>

IF you don't want the h1 to shift due to the scrollbar, you would have to calculate, using css calc() (and maybe some other things too), 50vw - (widthOfH1/2). This works because the vw unit (viewport width) is not affected by the scrollbar.
One way for the scrollbar to not affect the centering of the h1 would be to use JQuery.
$(#dictName).style.marginLeft = 'calc(50vw -'+(this.width/2)+'px)';
I haven't tested this so I'm not 100% sure if it will work, but please tell me if it does or doesn't. You may need to rerun this code when the button is pressed.

After some googling it seems I found the easiest way to solve this problem here, on SO:
How to prevent scrollbar from repositioning web page?
html {
overflow-y: scroll;
}
Probably, the question should be closed as duplicate, but I don't have enough reputation to do it.

Related

Measuring the space that text takes up when it extends past the boundaries of the div

I've been relentlessly trying to resize the text of my buttons to fit within the parent div, and have had no success with fitty and other external plug-ins which work inconsistently or not at all.
I'm attempting to make my own simplified version that simply reduces the font-size of my answer_button_1_text element by 1px until it's smaller than the parent answer_button_1 element.
Using clientWidth returns 281 for answer_button_1 and 253 for answer_button_1_text regardless of if the text in the button extends past the boundaries.
How can I get the actual length of the text?
I've attempted to use the canvas.measureText method, but am unfamiliar with using canvases and when I apply a canvas to the entire HTML in this codepen, none of the elements on my screen are visible. I'm sure I'm making a basic mistake, but if anyone could help me find a way to return the actual space that my answer_button_1_text element takes up, I would really appreciate it.
Here is a codepen:
https://codepen.io/TheNomadicAspie/pen/oNWpZrg
Here is my code:
<button id="button" class="button lower-button">
<div id="button_text">Really long button</div>
</button>
<div id="question_text">Test</div>
body {
background-color: gray;
}
.button {
display: block;
position: relative;
height: 20%;
width: 10%;
background-color: black; /*Button Color*/
color: #f5f5f5;
font-family: open_sans;
font-size: 1.5rem;
font-size: min(6vw, clamp(1rem, 4.5vh, 4rem));
border-radius: 20px;
text-decoration: none;
box-shadow: 0.1em 0.2em black;
transition: 0.2s;
}
.lower-button {
white-space: nowrap;
}
#question_text {
position: absolute;
color: blue;
font-size: 40px;
margin-top: 100px;
}
const question_text = document.getElementById('question_text')
let text_var = button.clientWidth + ' ' + button_text.clientWidth
question_text.innerText = text_var

Why is scrollWidth not including a child element's right margin?

I'm trying to have a <div> slide open to the minimum size required to contain its content without anything overflowing.
Here's what I've got so far:
window.onload = function() {
setTimeout(() => {
var thing = document.getElementById('thing');
thing.style.maxWidth = thing.scrollWidth + "px";
thing.style.maxHeight = thing.scrollHeight + "px";
}, 1000);
}
body {
background-color: black;
}
p {
margin: 40px;
padding: 0;
color: yellow;
background-color: green;
font-family: monospace;
}
div.expander {
margin: 0;
padding: 0;
max-width: 0;
max-height: 0;
overflow: hidden;
transition:
max-width 1s,
max-height 1s;
border: 1px solid red;
}
hr {
margin: 0;
padding: 0;
border-top: 1px solid blue;
border-right: none;
border-bottom: none;
border-left: none;
}
<div id="thing" class="expander">
<p>Hello, world!</p>
<hr>
<p>Goodbye, world!</p>
</div>
See how neither <p> is wide enough to contain its text without overflowing? That's what I'm trying to prevent. Clearly, scrollHeight is doing what I expect. Why isn't scrollWidth?
This isn't the full picture, but margin-right (or margin-left) gets ignored in specific scenarios. This is intended block functionality in CSS. From the specs:
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
If all of the above have a computed value other than 'auto', the values are said to be "over-constrained" and one of the used values will have to be different from its computed value. If the 'direction' property of the containing block has the value 'ltr', the specified value of 'margin-right' is ignored and the value is calculated so as to make the equality true. If the value of 'direction' is 'rtl', this happens to 'margin-left' instead.
In my opinion, this isn't very intuitive behavior and I prefer to avoid margins for block layout where possible (for more reasons than just this). So, you could add a wrapper <div> around your <p> tags and use padding instead. This also enables you to use a border between items instead of adding <hr> to your content. I think the proper semantics could go either way, depending on your real-world usage of this. To quote the MDN docs:
The HTML <hr> element represents a thematic break between paragraph-level elements: for example, a change of scene in a story, or a shift of topic within a section.
Historically, this has been presented as a horizontal rule or line. While it may still be displayed as a horizontal rule in visual browsers, this element is now defined in semantic terms, rather than presentational terms, so if you wish to draw a horizontal line, you should do so using appropriate CSS.
But, while that fixes a few concerns, that doesn't fix everything. The calculated width of the <p> elements is still less than min-content. So, we can force this with min-width: min-content;, or by using a different display value (probably on expander). This changes which algorithms are used for calculating widths under the hood.
Last note before the full example code: max-width and max-height are a decent trick but are really only useful for this kind of thing if you're trying to avoid modifying styles from JS (think :hover or adding and removing an .open class from JS, instead of setting width and height, directly)
setTimeout(() => {
const expander = document.querySelector('.js-expander');
expander.style.width = expander.scrollWidth + "px";
expander.style.height = expander.scrollHeight + "px";
}, 1000);
body {
background-color: black;
}
.expander {
display: grid;
width: 0px;
height: 0px;
overflow: hidden;
border: 1px solid red;
transition:
width 1s,
height 1s;
}
.expander-item {
padding: 40px;
font-family: monospace;
border-bottom: 1px solid blue;
}
.expander-item:last-child { border-bottom: 0px; }
.expander-item > * {
color: yellow;
background-color: green;
}
.expander-item > :first-child { margin-top: 0; }
.expander-item > :last-child { margin-bottom: 0; }
<div class="expander js-expander">
<div class="expander-item">
<p>Hello, world!</p>
</div>
<div class="expander-item">
<p>Goodbye, world!</p>
</div>
</div>
UPDATE: Based on comments, I thought I might include how <hr/> might be added back in:
setTimeout(() => {
const expander = document.querySelector('.js-expander');
expander.style.width = expander.scrollWidth + "px";
expander.style.height = expander.scrollHeight + "px";
}, 1000);
body {
background-color: black;
}
.expander {
display: grid;
width: 0px;
height: 0px;
overflow: hidden;
border: 1px solid red;
transition:
width 1s,
height 1s;
}
.expander-group {
padding: 40px;
font-family: monospace;
}
.expander-group > * {
color: yellow;
background-color: green;
}
.expander-group > :first-child { margin-top: 0; }
.expander-group > :last-child { margin-bottom: 0; }
.expander > hr {
margin: 0;
padding: 0;
border-top: 1px solid blue;
border-right: none;
border-bottom: none;
border-left: none;
}
<div class="expander js-expander">
<div class="expander-group">
<p>Hello, world 1!</p>
<p>Hello, world 2!</p>
</div>
<hr>
<div class="expander-group">
<p>Goodbye, world!</p>
</div>
</div>

Display a menu when hovering on the last character in the input in React

I am currently working on a form using React-Bootstrap that has a body that takes a message. This message shall include some tags selected from a dropdown menu. The thing is, this dropdown is to be displayed when the user enters an & and then, the user chooses an option from the menu that will replace the ampersand. I handled almost everything except the part of displayed the menu. How can I always show the menu at the last character entered by the user and also, how can I display it when hovering on this character. For example,
"Hi Dear, today we are going to work on &[The menu has to be displayed here when hovering on the ampersand]"
To be honest, I am quite confused and I just need to figure out how I should start. If there could be anything that helps, I'd be very grateful. Thanks in advance.
Regards.
Here is something i came up with.
To achieve this, first thing i thought of was to detect the caret position inside input or textarea.
I found this library and it worked perfectly.
https://github.com/bubkoo/get-cursor-position
Next task was to figure out how to place a menu inside input or textarea. For that i simply made a parent div and i set input 100% width and height of it & then we can place using any html tag inside that div using position: absolute and it will work like we adding stuff inside input tag.
The menu was added with top & left i got using that library. Rest of the code is basic, you can simple figure that out just checking it below.
Here is the code:
const menu = document.querySelector('.menu')
function showMenu(element) {
let lastChar = element.value[element.value.length - 1],
caret = getCaretCoordinates(element, element.selectionEnd);
if (lastChar === "&") {
menu.style.display = 'block';
menu.style.left = caret.left + 20 + 'px'
menu.style.top = caret.top + 20 + 'px'
} else {
menu.style.display = 'none'
}
}
function copyText(text) {
const input = document.querySelector('#input')
input.value += " " + text
menu.style.display = 'none'
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
transition: all 0.3s ease;
}
body {
height: 100vh;
width: 100vw;
display: grid;
place-content: center;
background-color: blueviolet;
}
.parent {
position: relative;
width: 500px;
height: 120px;
}
#input {
background-color: white;
width: 100%;
height: 100%;
border: none;
border-radius: 10px;
padding: 20px;
}
#input:focus {
border: 0;
outline: none;
}
.menu {
display: none;
position: absolute;
background-color: black;
color: white;
width: 100px;
}
.menu li {
text-align: center;
cursor: pointer;
height: 60px;
list-style: none;
display: grid;
place-content: center;
padding: 10px;
}
li:hover {
background: white;
;
color: black;
border: 1px solid black
}
<div class="parent">
<textarea id="input" oninput="showMenu(this)"></textarea>
<div class="menu">
<li onclick='copyText(this.innerText)'>Mango</li>
<li onclick='copyText(this.innerText)'>Banana</li>
<li onclick='copyText(this.innerText)'>Apple</li>
<li onclick='copyText(this.innerText)'>Orange</li>
<li onclick='copyText(this.innerText)'>Grapes</li>
</div>
</div>
<script src="https://rawgit.com/component/textarea-caret-position/master/index.js"></script>

CSS Formula for Precisely Offsetting Text

On my website, I am aligning a body of text precisely as exemplified in the following snippet.
html, body {
width: 100%;
height: 100%;
font-family: arial;
font-size: 48px;
text-transform: uppercase;
}
body {
margin: 0;
background: skyblue;
}
div {
width: 200px;
height: 100vh;
padding-top: calc(100vh - (1.5rem * 1.35));
box-sizing: border-box;
border: solid red 1px;
}
span {
line-height: 1.35;
display: inline-block;
border: solid black 1px;
}
<div><span>This</span> <span>is</span> <span>a</span><span>body</span><span>of</span> <span>text.</span></div>
However, I was hoping to take it one step further. For instance, I want to be able to place the top of the text as close as possible to, say, 60vh from the top of the page while still displaying half of the last line. Below is an example of what I mean in JS.
Note: Just noticed the second snippet does not display properly unless you open it to edit it. If you transfer it to codepen, it should work properly.
const
div = document.querySelector('div'),
span = document.querySelector('span'),
lineHeight = parseFloat(getComputedStyle(span).lineHeight),
target = innerHeight * 0.6,
remainder = (innerHeight - target) / lineHeight % 1 * lineHeight
div.style.paddingTop = target + remainder - lineHeight / 2 + 'px'
html, body {
width: 100%;
height: 100%;
font-family: arial;
font-size: 48px;
text-transform: uppercase;
}
body {
margin: 0;
background: skyblue;
}
div {
width: 200px;
height: 100vh;
position: absolute;
box-sizing: border-box;
border: solid red 1px;
}
span {
line-height: 1.5;
display: inline-block;
border: solid black 1px;
}
<div><span>This</span> <span>is</span> <span>a</span> <span>body</span> <span>of</span> <span>text.</span></div>
Notably, I know you can obviously find the "remainder" using calc, viewport units, and rem, but the rest is what is confusing because I am not great at math and also lacking sleep.
Hence I was hoping that somebody out there, who is better at math than me, would be able to tell me whether or not a pure CSS solution without preprocessors is possible (i.e. using only calc, viewport units, rem units, etc) before I waste any more time thinking about this. I know there are some nifty CSS formulas for fluid typography, but is something like this possible?
[ edit ] I thought about this some more while laying in bed. I do not believe it is possible without being able to calculate the "remainder." And there does not seem to be any way to calculate the "remainder" with only addition, subtraction, multiplication, and division. Please correct me if I am wrong.
The goal is to have the DIV tag be 100% of the document's height and then the text is offset a little bit within the DIV?
I think just adding another tag within the DIV to offset all the text can work. You said you want 60vh. Line Height should also be used when dealing with text height.
html, body {
width: 100%;
height: 100%;
font-family: arial;
font-size: 48px;
text-transform: uppercase;
}
body {
margin: 0;
background: skyblue;
}
div {
width: 200px;
height: 100vh;
box-sizing: border-box;
border: solid red 1px;
}
p
{ margin: 0;
padding-top: 60vh;
margin-top: -0.8em;
line-height: 1.6em;
}
span {
line-height: 1.35;
display: inline-block;
border: solid black 1px;
}
<html>
<body>
<div><p><span>This</span> <span>is</span> <span>a</span><span>body</span><span>of</span> <span>text.</span></p></div>
</body>
</html>
Or is this not quite it?

Floating menu, how to stick menu to the top?

I'm relatively new to js and fighting with floating menu.
This is how my js code look like
$(function(){
console.log('jest');
$(window).scroll(function(event){
console.log($('#menu').offset().top, $(this).scrollTop());
if ($('#menu').offset().top <= $(this).scrollTop()+$(window).height()) {
$('#menu').addClass("fixed");
} else {
$('#menu').removeClass("fixed");
}
});
});
When the top is achieved, fixed class is added properly.
My question is:
What should I do inside fixed class to make the menu stick to the top?
Nice an simple "position: sticky"..
brand {
display: block;
background-color: pink;
padding: 10px;
font-size: 20pt;
}
header {
background-color: yellow;
border: 2px solid black;
padding: 10px;
position: sticky;
top: 0;
}
section {
background-color: silver;
padding: 10px;
}
body {
padding: 0;
margin: 0;
}
<brand>
<div>This is our branding,. It can scroll away.</div>
<small>for all your header needs,.. </small>
</brand>
<header>
This is the header
</header>
<section>
Our othe stuff can go in here.<br><br><br><br><br><br><br><br><br><br>
Scroll down<br><br><br><br><br><br>
Even further<br><br><br><br><br>
A little bit more<br><br><br><br><br>
Ok I'm bored now.
</section>
<header>
This is repeated, see how the header takes over
</header>
<section>
Our othe stuff can go in here.<br><br><br><br><br><br><br><br><br><br>
Scroll down<br><br><br><br><br><br>
Even further<br><br><br><br><br>
A little bit more<br><br><br><br><br>
Ok I'm bored now.
</section>
.fixed{
position: fixed;
top: 0;
right: 0;
left: 0;
}

Categories

Resources