I'm given to understand that the <frameset> tag is deprecated as of HTML5. Thankfully, Chrome still supports rendering it, and unfortunately, it's currently the only thing I've found that fits my use case.
The important element of the <frameset> tag that other frame-like objects lack is draggable borders, which I haven't been able to get working with iframes even with a prohibitive amount of javascript assistance.
The other important thing in my case is that one of the frames contains a button/link that causes the other frame to disappear or reappear. When that happens, the frames should resize appropriately to fill the space.
My current HTML looks like the following MCVE:
index.html
<html>
<head>
<script language="javascript">
function toggleBottomFrame() {
var bottomFrame = document.getElementById("bottomFrame");
var horizFrameset = document.getElementById("horizFrameset");
if (bottomFrame.style.display == "none") {
bottomFrame.style.display = "";
horizFrameset.rows = "*,25%";
} else {
bottomFrame.style.display = "none";
horizFrameset.rows = "*,0px";
}
}
document.toggleBottomFrame = toggleBottomFrame;
</script>
</head>
<frameset id="horizFrameset" rows="*,0px">
<frameset id="vertFrameset" cols="300px,*">
<frame id="topLeftFrame" src="buttonpage.html"></frame>
<frame id="topRightFrame"></frame>
</frameset>
<frame id="bottomFrame" style="display:none"></frame>
</frameset>
</html>
buttonpage.html
<html>
<head></head>
<body>
<button onclick="parent.frameElement.ownerDocument.toggleBottomFrame();">
</body>
</html>
This works both in the IE11 that the code was initially written for (and needs to continue to support), as well as in Chrome.
How do I implement the exact same functionality (including, most importantly, the ability to drag around the borders of the frames with my mouse to expand or shrink one of the frames) using non-deprecated functionality?
If possible, I'd like a solution in standard client-side JS or HTML, without needing to import another library like resize.js. This is meant for a very lightweight frontend, and I don't want to bloat it down with libraries I don't need.
You should be able to achieve the shrink and grown functionality using the flex layout. Below 2 approaches may work. Both the approaches has the right section and bottom section as iframe and the left section has button to show and hide the right and bottom sections.
Option 1
Using flex and using the css resize property.
Drawback is that you will need to resize using the resize button shown at the bottom right corners. The left section's bottom right corner can be used for horizontal resizing and the right section's bottom right corner can be used for vertical resizing. Note that due to the iframe contents the right section's bottom right corner resize button may not be visible, but if you bring the cursor to the bottom right you will see the cursor changing to resize and allowing you to resize.
function toggleBottom() {
if (document.getElementById('bottomFrame').clientHeight > 0) {
document.getElementById('topFrame').style.height = '100%';
} else {
document.getElementById('topFrame').style.height = '80%';
}
}
function toggleRight() {
if (document.getElementById('topRightFrame').clientWidth > 0) {
document.getElementById('topLeftFrame').style.width = '100%';
} else {
document.getElementById('topLeftFrame').style.width = '50%';
}
}
html,
body {
height: 98%;
}
.page-container {
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex-direction: row;
resize: vertical;
border: 1px solid #000;
overflow: hidden;
}
.container-top {
height: 80%;
}
.container-bottom {
flex: 1 1;
overflow: hidden;
}
.container-left {
width: 30%;
border: 1px solid #000;
resize: horizontal;
overflow: hidden;
}
.container-right {
flex: 1 1;
height: 100%;
border: 1px solid #000;
overflow: hidden;
display: flex;
}
.frame-right {
flex: 1 1;
}
.frame-bottom {
flex: 1 1 100%;
border: 1px solid #000;
}
<html>
<body class="page-container">
<div class="container container-top" id="topFrame">
<div class="container-left" id="topLeftFrame">
<button onclick="toggleBottom()">Toggle Bottom</button>
<button onclick="toggleRight()">Toggle Right</button>
</div>
<div class="container-right" id="topRightFrame" >
<iframe src="https://stackoverflow.com" class="frame-right">
</iframe>
</div>
</div>
<div class="container container-bottom" id="bottomFrame">
<iframe class="frame-bottom" src="https://stackoverflow.com"></iframe>
</div>
</body>
</html>
Option 2
Using flex and using some scripting we should be able to make the whole border draggable. This is inspired from the answer in https://stackoverflow.com/a/53220241/2772300
const topRightFrame = document.getElementById("topRightFrame");
const topLeftFrame = document.getElementById("topLeftFrame");
const bottomFrame = document.getElementById("bottomFrame");
const topFrame = document.getElementById("topFrame");
const borderSize = 4;
function toggleBottom() {
if (bottomFrame.clientHeight > borderSize) {
topFrame.style.height = '100%';
} else {
topFrame.style.height = '80%';
}
}
function toggleRight() {
if (topRightFrame.clientWidth > borderSize) {
topLeftFrame.style.width = '100%';
} else {
topLeftFrame.style.width = '50%';
}
}
let mousePosition;
function resizeHorizontal(e){
const dx = mousePosition - e.x;
mousePosition = e.x;
topLeftFrame.style.width = (parseInt(getComputedStyle(topLeftFrame, '').width) - dx) + "px";
}
topRightFrame.addEventListener("mousedown", function(e){
if (e.offsetX < borderSize) {
mousePosition = e.x;
document.addEventListener("mousemove", resizeHorizontal, false);
}
}, false);
document.addEventListener("mouseup", function(){
document.removeEventListener("mousemove", resizeHorizontal, false);
}, false);
function resizeVertical(e){
const dy = mousePosition - e.y;
mousePosition = e.y;
topFrame.style.height = (parseInt(getComputedStyle(topFrame, '').height) - dy) + "px";
}
bottomFrame.addEventListener("mousedown", function(e){
if (e.offsetY < borderSize) {
mousePosition = e.y;
document.addEventListener("mousemove", resizeVertical, false);
}
}, false);
document.addEventListener("mouseup", function(){
document.removeEventListener("mousemove", resizeVertical, false);
}, false);
html,
body {
height: 98%;
}
.page-container {
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex-direction: row;
overflow: hidden;
}
.container-top {
height: 80%;
}
.container-left {
width: 50%;
overflow: hidden;
height: 100%;
}
.container-right {
flex: 1 1;
height: 100%;
overflow: hidden;
display: flex;
padding-left: 4px;
background-color: #ccc;
cursor: ew-resize;
}
.frame-right {
flex: 1 1;
}
.container-bottom {
flex: 1 1;
overflow: hidden;
padding-top: 4px;
background-color: #ccc;
cursor: ns-resize;
}
.frame-bottom {
flex: 1 1 100%;
}
iframe {
border: 0;
}
<html>
<body class="page-container">
<div class="container container-top" id="topFrame">
<div class="container-left" id="topLeftFrame">
<button onclick="toggleBottom()">Toggle Bottom</button>
<button onclick="toggleRight()">Toggle Right</button>
</div>
<div class="container-right" id="topRightFrame" >
<iframe src="https://stackoverflow.com" class="frame-right">
</iframe>
</div>
</div>
<div class="container container-bottom" id="bottomFrame">
<iframe class="frame-bottom" src="https://stackoverflow.com"></iframe>
</div>
</body>
</html>
Have you looked a Golden Layout to do the resizing? You could then place iframes inside to match the size of the containing div.
Sorry this not a more complete answer, but though this might be an area worth exploring that is not likely to come up.
Related
I found this script for resizing divs vertically.
How do you allow a user to manually resize a <div> element vertically?
I was able to use it, but now I need to modify it to make sure to resize another div horizontally.
I tried to modify it but the results are not what I wanted, some traits don't work well.
For example:
let blockH = document.querySelector("#div1"),
sliderH = document.querySelector(".sliderH");
sliderH.onmousedown = function dragMouseDown(e) {
let dragX = e.clientX;
document.onmousemove = function onMouseMove(e) {
blockH.style.width = blockH.offsetWidth + dragX + "px";
dragX = e.clientX;
}
document.onmouseup = () => document.onmousemove = document.onmouseup = null;
}
<div class="container">
<div class="block" id="div1">
Block 1
</div>
<div class="sliderH"></div>
<div class="block" id="div2">
Block 2
</div>
</div>
#div2{
flex: 1;
}
#div1{
resize: horizontal;
overflow: auto;
}
.sliderH {
cursor: col-resize;
user-select: none;
width: 10px;
}
.container {
display: flex;
flex-direction: row;
width: 100%;
}
But don't work very good.
Someone can help me to edit the script for horizontally resizing?
Thank you
I am trying to transition the #two element from height: auto to its contents height.
Based on this, I have came up with the below code.
It works, but there is an unpleasant side-effect: the content will be created first and only then parent div will start to adapt its width.
How can I correct that? I am also open to pure CSS, non-JS solutions.
let fill_button = document.getElementById('fill')
let div_to_fill = document.getElementById('two')
fill.addEventListener('click', function() {
fill_parent_with_some_content(div_to_fill)
})
function fill_parent_with_some_content(parent) {
let content_height = '200px'
// create new element
let content = document.createElement('div')
content.style.margin = '0'
content.style.height = content_height
content.style.width ='300px'
content.style.background = 'orange'
// height transition from auto
parent.style.height = getComputedStyle(parent).height
parent.style.transition = 'height 2s ease-in-out'
parent.offsetHeight // force repaint
parent.style.height = content_height
parent.appendChild(content)
}
#one, #two, #three {
background: white;
border: 1px solid black;
margin-top: 10px;
padding: 0;
}
#one, #three {
height: 100px;
}
#two {
height: auto;
}
<!DOCTYPE HTML>
<html>
<head>
</head>
<style>
</style>
<body>
<button id="fill">Fill second div with some content</button>
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
</body>
</html>
I have a header with a logo. This logo should appear only if the site has been scrolled.
I tried this in javascript:
if(document.getElementById("div").scrollTop != 0){
document.write("<img src='logo.jpg'>");
}
But this did not work.
How to achieve it?
Use window.addEventListener('scroll', callback) and then set the value "block" to the img's property.
window.addEventListener('scroll', function(e) {
if (document.getElementsByTagName("html")[0].scrollTop > 5) {
document.getElementsByClassName('imgHeader')[0].style.display = "block";
} else {
document.getElementsByClassName('imgHeader')[0].style.display = "none";
}
});
.imgHeader {
height: 100px;
width: 100px;
display: none;
}
div {
height: 1000px;
}
header {
position: fixed;
top: 0;
width: 100%;
}
<header><img class="imgHeader" src="https://material.angular.io/assets/img/examples/shiba1.jpg" /></header>
<div></div>
Try this one
$(document).on("scroll", function() {
if ($(document).scrollTop() > 5) {
$(".below-top-header").addClass("show-class");
} else {
$(".below-top-header").removeClass("show-class");
}
});
.content {
height: 500px;
}
.show-class {
position: fixed;
display: block !important;
}
.hide-class {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content">
<div class="below-top-header hide-class">
Image
</div>
</div>
Unfortunately, I think you must use some JavaScript to make it work like you want.
Here is an easy snippet to show the principle I used:
Start with the logo already in the html, but with display: none in its CSS,
Use window.addEventListener('scroll', callback) to change display: none to display: block when the page is scrolled down (i.e. document.documentElement.scrollTop > 0).
var logo = document.getElementById('logo');
window.addEventListener('scroll', function(e) {
if (document.documentElement.scrollTop > 0) {
logo.style.display = 'block';
}else logo.style.display = 'none';
});
#logo {
display: none;
position: fixed;
top: 0;
background: #aaa;
}
#page {
background: #ddd;
height: 2000px;
}
<div id='logo'><img src='http://placekitten.com/200/50'></div>
<div id='page'>Start of page<br>Try to scroll down</div>
Hope it helps.
You need to add an scrollListener to the window in order to execute code when the user scrolls.
Your code only gets executed on page load.
Informations on Eventlisteners: https://developer.mozilla.org/de/docs/Web/API/EventTarget/addEventListener
window.addEventListener('scroll', function(e) {
//do something as soon as the window was scrolled
});
Be aware that the event will be triggered each time the user scrolls.
If you take a look at KIOSK WEBSITE HERE they have the 'WE ARE OPEN" circular type in javascript (I know how to do that) but what I don't know is how to achieve that when scrolling. Like how does the text move when scrolling up or down. How do you get that in HTML/CSS/JS ?
View the code I worked on here https://codepen.io/noel_emmanuel/pen/WJxRZW
HTML:
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
CSS:
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
}
JS:
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
OPEN FOR SUGGESTIONS.
You could rotate this on a scroll event. This simply rotates the div depending on how far from the top of the page you have scrolled.
I added a height and width to the text, as well as positioned it fixed to see the effect.
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
$(document).ready(function(){
$(window).scroll(function(e){
rotateText();
});
function rotateText(){
var scrolled = $(window).scrollTop();
$('div.circTxt').css('transform','rotate('+scrolled+'deg)');
}
});
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
height: 4000px;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
position: fixed;
height: 200px;
width: 200px;
transform-origin: 0% 59%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
This is a simple HTML placeholder for a thing I am working on.
You can ignore the rest (I hope!) and focus on this sole issue:
The zoom on the image works, and it focus on the quadrant you press on, as I want it to. But it only places top and bottom scroll bars if the zoom is made on the top left quadrant.
I want it to always show the scroll bars. What am I missing?
Thanks
var images = ["Species_copy_number.png", "Species_coverage.png", "Species_distribution.png", "Gene_copy_distribution.png"];
var descriptions = ["cariño", "muis bueno", "caliente", "CABRÓN!"];
var titles = ["ay", "ay ay", "ay ay ay", "AY AY AY MI HIJJJJJJOOOOOOOOOOOOO"];
function changeImage(index){
var img = document.getElementById("img_place");
img.src = "Figures/" + images[index];
document.getElementById("desc_place").textContent = descriptions[index];
document.getElementById("subtitle").textContent = titles[index];
}
window.zoomedIn = false;
window.onload = function(){
var canvas = document.getElementById("img_wrapper");
canvas.onclick = function(event){
var imgWrapper = this, zoomContainer = document.getElementById("zoom-container");
var imgPlace = document.getElementById("img_place");
if (window.zoomedIn) {
imgPlace.setAttribute("style", "transform :\"\"");
window.zoomedIn = false;
} else {
var width = zoomContainer.offsetTop + zoomContainer.offsetWidth;
var height = zoomContainer.offsetTop + zoomContainer.offsetHeight;
var tro = (zoomContainer.offsetTop + event.clientY > height / 2) ? "bottom" : "top";
tro += (zoomContainer.offsetLeft + event.clientX > width / 2) ? " right" : " left";
imgPlace.setAttribute("style", "transform-origin: "+ tro + " 0px; transform: scale(2);");
window.zoomedIn = true;
}
}
}
body, html { height: 100%; }
.flex-container {
display: -webkit-flex;
display: -ms-flex;
display: -moz-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.flex-item {
display: -webkit-flex;
display: -ms-flex;
display: -moz-flex;
display: flex;
margin: 3px;
padding: 0 0 10px;
}
.flex-item img{
width: 100%;
}
span {
min-width: 5em;
margin-top: 3em;
padding-right: 1em;
}
a {
padding-left: 0.3em;
}
.img-wrapper {
border: 1px solid gray;
}
img {
height: 100%;
width: 100%;
}
#zoom-container{
overflow: auto;
}
<h1>Mega title</h1>
<h2 id="subtitle">Title</h2>
<div class="flex-container">
<div class="flex-item">
<span>
cenas<br>
Img #1
Img #2
cenas<br>
Img #3
Img #4
</span>
<div id="zoom-container">
<div id="img_wrapper" class="img-wrapper">
<img id="img_place" src="https://i.ytimg.com/vi/ddqvuwXBK5k/maxresdefault.jpg"/>
</div>
</div>
</div>
</div>
<h2>Description</h2>
<span id="desc_place">Description</span>
The coordinate system starts from left upper corner of the parent element. Since you are transforming the origin of the image in your quadrant on click, you are starting it from a clipped point.
With regard to document flow directions, the top and left sides are the block-start and inline-start sides and browsers or UA behave as though content is clipped beyond that direction.
From W3C specs: Scrolling Origin, Direction, and Restriction
Due to Web-compatibility constraints ... UAs must clip the scrollable overflow region of scroll containers on the block-start and inline-start sides of the box (thereby behaving as if they had no scrollable overflow on that side).
There may be a JS hack. I am not sure.
Here are some work-arounds (with) better explanations.
CSS Transforms / JS to zoom into element
Canvas Method
The best I could think of in your case is to add this CSS for .img-wrapper
.img-wrapper {
height: 100%;
width: 100%;
overflow: auto
}
and add overflow: auto; to imgPlace.setAttribute()in your last else statement
imgPlace.setAttribute("style", "transform-origin: "+ tro + " 0px; transform: scale(2);position: relative;overflow: auto;");
That way you will get scroll bars in quadrant 1, 2 and 3. In the fourth quadrant scroll restriction will be enabled.
Here is a codepen edit of your code
Simply create two new classes in css
.zoomed {
transform:scale(2);
}
.scroll {
overflow:scroll;
}
Add some jquery code
$ ('#img_wrapper').click(function() {
var top = $('#img_place').height() / 2;
$('#img_place').toggleClass('zoomed');
$(this).toggleClass('scroll');
if ($('#img_place').hasClass('zoomed')) {
$('#img_place').css('top', top);
}
else {
$('#img_place').css('top', '0');
}
});
Here is Updated fiddle chek out this.
Hope it's fine for you