Many checkbox elements "slows" down Safari - html

I am encountering an issue, in Safari. When I have many type="checkbox" elements on a page, interacting with with a text input becomes very slow and laggy.
This seems much more severe in Safari than Chrome/Firefox (on Mac).
I noticed the performance issue when doing some filtering on the massive list that contains checkboxes, but noticed that even if I remove my filtering code, the performance is still very poor.
Snippet #1
1600 type="checkbox" elements. Try interacting with the text input on Safari - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
input.type = "checkbox";
p.appendChild(input);
document.getElementById("container").appendChild(p);
}
}
make();
<input type="text">
<div id="container">
</div>
Snippet #2
1600 span elements; interacting with the text input is as smooth as usual in Safari - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
input.type = "checkbox";
p.appendChild(input);
document.getElementById("container").appendChild(p);
}
}
function make2() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var sp = document.createElement("span");
sp.innerHTML = Math.floor(Math.random() * 1600);
p.appendChild(sp);
document.getElementById("container").appendChild(p);
}
}
make2();
<input type="text">
<div id="container">
</div>
Is there anyway I can remedy this issue in Safari and get the performance closer to how Firefox and Chrome handle this?

Summary:
From my understanding of your question, your stating the webpage performance is lost when you use checkboxes over spans, and would like to know why this may be
Answer
You have an unusually high number of form checkboxes, whilst a browser can quite easily handle more form elements, it will ultimately depend on how much RAM you have available and installed on that terminal.
There is no official limit to the number of DOM elements you can have on a website, the only thing I can suggest is to use AJAX and pagination to break down the number of checkboxes you have on 1 page at any given time or upgrade your computer.
I have checked out the links you profiled to JSFiddle and did not have any issues with lag typing into the text box myself.
I dont feel this is an HTML question, but rather a memory / performance issue
Check to see how much memory you have, how much memory you have free and available and if there is an issue with your version of your browser that may be causing a memory lag. For instance Firefox has been notoriously known for causing memory issues when left running for a while.

The issue seems to lie with displaying the Safari checkbox. If the checkboxes exist in the dom but are hidden, by using display: none, the performance degradation is gone.
While I don't understand exactly why this is occuring, I can essentially resolve the issue by using custom checkbox element and applying the display: none property on the original.
Snippet - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
var l = document.createElement("label");
var c = "c-" + Math.floor(Math.random() * 1600);
input.type = "checkbox";
l.htmlFor = c;
input.id = c;
p.appendChild(input);
p.appendChild(l);
document.getElementById("container").appendChild(p);
}
}
function make2() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var sp = document.createElement("span");
sp.innerHTML = Math.floor(Math.random() * 1600);
p.appendChild(sp);
document.getElementById("container").appendChild(p);
}
}
make();
input[type=checkbox] {
display: none;
}
label {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 50%;
display: block;
height: 12px;
width: 12px;
margin-bottom: 4px;
position: relative;
}
label:after {
background: red;
border-radius: 50%;
content: "";
position: absolute;
height: 8px;
width: 8px;
top: 2px;
left: 2px;
display: none;
}
input[type=checkbox]:checked + label {
border-color: red;
}
input[type=checkbox]:checked + label:after {
display: block;
}
<input type="text">
<div id="container">
</div>

Related

Scrolling parent of display:grid unexpectedly scrolls when a child's grid-row-start changes

We have a list with cells that have explicit grid-rows/columns set inside a grid which is inside a scrollable element. We draw a selection border over a number of these cells.
When the scrolling element is not scrolled all the way to the top, changing the selection element's grid-row-start causes the scrolling area to scroll to the point where the offset of the top of the selection element in relation to the viewport is maintained. In other words, if the selection element is 100px from the top of the viewport, and you click on a cell lower down on the page, the scroll element will scroll down until the selection element is 100px from the top of the viewport again.
This usually happens. Sometimes it doesn't on a fresh page. But click on the scrollbar and scrolling a teeny bit causes this behavior to start happening again. This leads me to believe this is a browser bug and not intended behavior, but it repros in Chrome, Edge, AND FireFox.
You can even open the F12 tools and modify grid-row-start manually, and the scrolling behavior occurs.
Sample code is below. I've found a workaround, which is commented out, but it is not ideal. To replicate the "bug", scroll down a bit then start clicking on cells.
Is this intended behavior? What's causing it? Any easy way to avoid it?
Thanks!
window.onload = () => {
const list = document.getElementById('list');
const numRows = 100;
const numColumns = 8;
for (let i = 0; i < numRows; i++) {
let row = document.createElement('div');
row.className = 'row';
row.style.gridRow = String(i + 1);
for (let j = 0; j < numColumns; j++) {
let cell = document.createElement('div');
cell.className = 'cell';
cell.style.gridRow = String(i + 1);
cell.style.gridColumn = String(j + 1);
cell.innerText = `${i} - ${j}`;
cell.onclick = () => {
const selection = document.getElementById('selection');
selection.style.gridArea = `${i+1} / ${j+1} / ${i+2} / ${j+2}`;
/*
selection.style.display = 'none';
setTimeout(() => {
document.getElementById('selection').style.display = '';
}, 0);
*/
};
row.appendChild(cell);
}
list.appendChild(row);
}
};
.list {
display: grid;
}
.row {
display: contents;
}
.cell {
outline: 1px solid black;
padding: 12px 4px;
}
.selection {
outline: 5px solid green;
grid-area: 20 / 4 / 21 / 5;
z-index: 1;
}
<div class='list' id='list'>
<div class='selection' id='selection'></div>
</div>

How to select elements by css property

I have a third party library that add texts to my angular app, and I want to style it, unfortunately there is no class or specific element name to do css selector by.
My question is if is it possible to do css selector based on css property.
For example select all elements that are bold
I tried this but doesn't work and I get SassError: Expected identifier
ngx-contentful-rich-text {
line-height: 2rem;
*[font-weight=700] {
margin-top: 2rem;
}
}
You might want to use this:
var paragraphs = document.getElementsByTagName('p');
function change() {
var paragraphs = document.getElementsByTagName('p');
for (i = 0; i < paragraphs.length; i++) {
if (getComputedStyle(paragraphs[i]).fontWeight == 700) {
paragraphs[i].style.backgroundColor = '#00ff00';
}
}
}
Snippet:
function change() {
var paragraphs = document.getElementsByTagName('p');
for (i = 0; i < paragraphs.length; i++) {
if (getComputedStyle(paragraphs[i]).fontWeight == 700) {
paragraphs[i].style.backgroundColor = '#00ff00';
}
}
}
<button onclick="change()">Change!</button>
<p style="font-weight:400;">Will not change.</p>
<p style="font-weight:700;">Will change.</p>

Internet Explorer Static GridView issues

I am having some really weird issues with my static GridView Header. The lines in IE aren't lining up properly; some of them do, and others do not. Can some one help me out? It works perfectly in Chrome, just not IE.
Chrome:
IE:
Here is my relevant code.
<script type="text/javascript">
function MakeStaticHeader(gridId, height, width, headerHeight, isFooter) {
var tbl = document.getElementById(gridId);
if (tbl) {
var DivHR = document.getElementById('DivHeaderRow');
var DivMC = document.getElementById('DivMainContent');
var DivFR = document.getElementById('DivFooterRow');
//*** Set divheaderRow Properties ****
DivHR.style.height = headerHeight + 'px';
DivHR.style.width = (parseInt(width) - 50) + 'px';
DivHR.style.position = 'relative';
DivHR.style.top = '0px';
DivHR.style.left = (tbl.clientLeft-25) +'px';
DivHR.style.zIndex = '10';
DivHR.style.verticalAlign = 'top';
DivHR.style.alignContent = 'center';
//*** Set divMainContent Properties ****
DivMC.style.width = width + 'px';
DivMC.style.height = height + 'px';
DivMC.style.position = 'relative';
DivMC.style.top = -headerHeight + 'px';
DivMC.style.zIndex = '1';
//****Copy Header in divHeaderRow****
DivHR.appendChild(tbl.cloneNode(true));
}
}
function OnScrollDiv(Scrollablediv) {
document.getElementById('DivHeaderRow').scrollLeft = Scrollablediv.scrollLeft;
//if (document.getElementById('DivHeaderRow').scrollLeft >= 300) {
// document.getElementById('DivHeaderRow').scrollLeft = 300;
//}
}
</script>
CSS
html, body {
margin:0px;
padding:0px;
width: 100%;
box-sizing: border-box;
}
CSS Header Style
.GVFixedHeader
{
font-weight: bold;
background-color: Green;
position: relative;
font-size: 12px;
text-align: left;
}
It has to do with how IE renders a GridView. I would custom change my formating on one cell of the table, but that would mess with IE and change the default settings. Chrome would correctly identify that I only wanted to add style not change completely.
for (int i = 0; i < e.Row.Cells.Count; i++)
{
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[i].Attributes.Add("style", "white-space: inital;");
e.Row.Cells[i].Attributes.Add("style", "text-align: left;");//THIS IS WHAT I ADDED + some altering of the width of the JS
if (i == 1)
{
e.Row.Cells[i].Text = "Make Inactive?";
}
if (i == 9)
{
e.Row.Cells[i].Text = "Total Invoice YTD";
e.Row.Cells[i].Attributes.Add("style", "white-space: normal;");
}
if (i == 13)
{
e.Row.Cells[i].Attributes.Add("style", "white-space: normal;");
}
}
if (e.Row.RowType == DataControlRowType.DataRow) { e.Row.Cells[i].Attributes.Add("style", "white-space: nowrap;"); } //ALWAYS makes sure there is no wrapping of text
}

Auto hide rows in HTML table when entire row is empty

In a HTML table how can I auto hide an entire row if all the cells (columns) within that row are empty?
I presume there is something I can add to the tag that would do this, but I cannot seem to find a solution anywhere.
In HTML, you can use the hidden attribute, as in <tr hidden>, but this is an HTML5 novelty and has limited browser support. But if you can directly change the HTML markup, the best way to hide an element is to remove it.
Assuming you want something that still lets you have the row there in the markup, for some reason, then you can use JavaScript e.g. as follows:
<script>
function emptyCellsOnly(row) {
var cells = row.cells;
for(var j = 0; j < cells.length; j++) {
if(cells[j].innerHTML !== '') {
return false;
}
}
return true;
}
var rows = document.getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++) {
if(emptyCellsOnly(rows[i])) {
rows[i].style.display = 'none';
}
}
</script>
The test if(cells[j].innerHTML !== '') checks whether cell is completely empty, as in <td></td>. A space character, or a line break, is not counted as empty. If they should be, modify the condition as needed.
The code rows[i].style.display = 'none' hides the row by setting its display property to none, so CSS-enabled browsers will show the page as if the element were not there, but it is still accessible to scripts, etc. You could alternative remove the element completely from the DOM.
You can use a javascript like this
$('tr').each(function() {
if($(this).find('td').length == 0) {
$(this).hide();
}
});
After some research I found this sollution, which has the advantage over empty-cells:hide, that it completely removes the space an empty cell would take up.
<style type="text/css">
table {
border-spacing: 0px; // removes spaces between empty cells
border: 1px solid black;
}
tr, td {
border-style: none; // see note below
padding: 0px; // removes spaces between empty cells
line-height: 2em; // give the text some space inside its cell
height: 0px; // set the size of empty cells to 0
}
</style>
Unfortunately you have to set border-style: none;, else the borders of empty cells will be painted anyway (which results in thick lines).
I tried additional code like:
td:empty {
display: none;
border-style: none;
}
But in my table of 2 columns it removes the borders of either the left or the right column, but never of both...
Any hint at how to remove the borders of empty rows would be appreciated.
in my case cells have Spaces tabs . they are not data.
areAllCellsEmpty : true if, all cells.textContent are empty or Whitespace
innerHTML didnt give the result i wanted.
usage:
hideEmptyRows_ofTableById("myTable_id"); /* <- your table id here */
code:
function isEmptyOrSpaces(str){
return str === null || str.trim() === '' ;
}
function areAllCellsEmpty(row) {
var cells = row.cells;
var anyCellFull = false;
for(var j = 0; j < cells.length; j++) {
if( ! isEmptyOrSpaces(cells[j].textContent) ) {
anyCellFull =true;
break;
}
}
return !anyCellFull;
}
function hideEmptyRows_ofTableById(elem_id){
var table = document.getElementById(elem_id);
var rows = table.getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++) {
if( areAllCellsEmpty(rows[i]) ) {
rows[i].style.display = 'none';
}
}
}

Trouble with html5 audio progress bar/tribbles

I'm adapting this progress bar:http://www.richardshepherd.com/tv/audio/ to work with my playlist code, but I can't work out why it's not working. I expect it's something ridiculous (I tried adding the (document).ready function, but that broke the rest of my code).
This is what I have:
function loadPlayer() {
var audioPlayer = new Audio();
audioPlayer.controls="controls";
audioPlayer.preload="auto";
audioPlayer.addEventListener('ended',nextSong,false);
audioPlayer.addEventListener('error',errorFallback,true);
document.getElementById("player").appendChild(audioPlayer);
nextSong();
}
function nextSong() {
if(urls[next]!=undefined) {
var audioPlayer = document.getElementsByTagName('audio')[0];
if(audioPlayer!=undefined) {
audioPlayer.src=urls[next];
audioPlayer.load();
audioPlayer.play();
next++;
} else {
loadPlayer();
}
} else {
alert('the end!');
}
}
function errorFallback() {
nextSong();
}
function playPause() {
var audioPlayer = document.getElementsByTagName('audio')[0];
if(audioPlayer!=undefined) {
if (audioPlayer.paused) {
audioPlayer.play();
} else {
audioPlayer.pause();
}
} else {
loadPlayer();
}
}
function stop() {
var audioPlayer = document.getElementsByTagName('audio')[0];
audioPlayer.pause();
audioPlayer.currentTime = 0;
}
function pickSong(num) {
next = num;
nextSong();
}
var urls = new Array();
urls[0] = '01_horses_mouth/mp3/01. Let The Dog See The Rabbit preface.mp3';
urls[1] = '01_horses_mouth/mp3/02. The Other Horse\'s Tale.mp3';
urls[2] = '01_horses_mouth/mp3/03. Caged Tango.mp3';
urls[3] = '01_horses_mouth/mp3/04. Crumbs.mp3';
urls[4] = '01_horses_mouth/mp3/05. Mood Elevator Reprise.mp3';
urls[5] = '01_horses_mouth/mp3/06. Mood Elevator.mp3';
var next = 0;
// Display our progress bar
audioPlayer.addEventListener('timeupdate', function(){
var length = audioPlayer.duration;
var secs = audioPlayer.currentTime;
var progress = (secs / length) * 100;
$('#progress').css({'width' : progress * 2});
var tcMins = parseInt(secs/60);
var tcSecs = parseInt(secs - (tcMins * 60));
if (tcSecs < 10) { tcSecs = '0' + tcSecs; }
$('#timecode').html(tcMins + ':' + tcSecs);
}, false);
I end up getting the default player which works fine, as do my own play/pause and stop buttons, but the progress bar does nothing.
Oh, and this is what I've stuck in my css:
#progressContainer {position: relative; display: block; height: 20px;
background-color: #fff; width: 200px;
-moz-box-shadow: 2px 2px 5px rgba(0,0,0,0.4);
-webkit-box-shadow: 2px 2px 5px rgba(0,0,0,0.4);
box-shadow: 2px 2px 5px rgba(0,0,0,0.4);
margin-top: 5px;}
#progress {
display: block;
height: 20px;
background-color: #99f;
width: 0;
position: absolute;
top: 0;
left: 0;}
and this is the html:
<div id="player" >
<span id="timecode"></span>
<span id="progressContainer">
<span id="timecode"></span>
<span id="progress"></span>
</div>
The page is here: http://lisadearaujo.com/clientaccess/wot-sound/indexiPhone.html
Please note that this is only working with the media query for iPhone portrait orientation, so if you look at it on a desktop, you'll need to squeeze your window up. :-)
I've now gone with a different solution (http://www.adobe.com/devnet/html5/articles/html5-multimedia-pt3.html) which explained how to acheive this a little better for me. I'm a copy/paster so have very little clue about the correct order in which things must go. What I've got now is this:
function loadPlayer() {
var audioPlayer = new Audio();
audioPlayer.controls="controls";
audioPlayer.preload="auto";
audioPlayer.addEventListener('ended',nextSong,false);
audioPlayer.addEventListener('error',errorFallback,true);
audioPlayer.addEventListener('timeupdate',updateProgress, false);
document.getElementById("player").appendChild(audioPlayer);
nextSong();
}
var urls = new Array();
urls[0] = '01_horses_mouth/mp3/01. Let The Dog See The Rabbit preface.mp3';
urls[1] = '01_horses_mouth/mp3/02. The Other Horse\'s Tale.mp3';
urls[2] = '01_horses_mouth/mp3/03. Caged Tango.mp3';
urls[3] = '01_horses_mouth/mp3/04. Crumbs.mp3';
urls[4] = '01_horses_mouth/mp3/05. Mood Elevator Reprise.mp3';
urls[5] = '01_horses_mouth/mp3/06. Mood Elevator.mp3';
var next = 0;
function updateProgress()
{
var audioPlayer = document.getElementsByTagName('audio')[0];
var value = 0;
if (audioPlayer.currentTime > 0) {
value = Math.floor((100 / audioPlayer.duration) * audioPlayer.currentTime);
}
progress.style.width = value + "%";
}
Hurray. It works. I am not entirely sure why, but that's OK for now...