Welcome to our free JavaScript tutorial. This tutorial is based on Webucator's Introduction to JavaScript Training course.
We can use JavaScript to both retrieve information about element's CSS styles and to set those styles programmatically.
Lesson Goals
Throughout this course we've changed the style of a DOM element with JavaScript - setting the background color of the page, say, or altering the text color of an element. Typically, we use the following syntax:
element.style.cssproperty = 'cssvalue';
where element
might be a DOM element gotten from its id
(via getElementById()
), cssproperty
something like color
(to set the text color), and cssvalue
something like red
. We can both get and set any styles for most any element.
Each CSS property has a corresponding property of the JavaScript style
object:
color
) then the JavaScript property is the same (e.g., style.color
).background-color
) then the JavaScript property uses lower camel case (e.g., style.backgroundColor
).The style
object is a collection of an element's styles that are either defined within that HTML element's style
attribute or directly in JavaScript. Styles defined in the <style>
tag or in an external style sheet are not part of the style
object.
The W3C specifies a method for getting at the current (or actual) style of an object: the window
object's getComputedStyle()
method.
window.getComputedStyle(Element)
Note that the reference to window
can be excluded as window
is the implicit object. For example:
var div = document.getElementById("divTitle"); var computedStyle = getComputedStyle(div); alert(computedStyle.fontWeight); var curStyle = getComputedStyle(div); alert(curStyle.fontWeight);
Using this method - with getComputedStyle()
, as opposed to element.style
- we can get for any element the styles set with inline CSS, from CSS in the head
of the page, or in an external stylesheet. Furthermore, as the name of the method getComputedStyle()
suggests, these are computed (calculated) styles: whereas element.style
just gives us style info as set in CSS, getComputedStyle()
gives us the real-time calculated CSS.
Let's take a look at a simple example to make this more clear.
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Styles</title> <link href="customstyles.css" rel="stylesheet"> <script> window.onload = function() { document.getElementById("getstyles").addEventListener("click", function() { var pgraph = document.getElementById("pgraph"); var styleString = "Styles\n"; styleString += 'color: ' + pgraph.style.color + "\n"; styleString += 'margin: ' + pgraph.style.margin + "\n"; styleString += 'padding: ' + pgraph.style.padding + "\n"; styleString += 'border: ' + pgraph.style.borderBottom + "\n"; styleString += 'width: ' + pgraph.style.width + "\n"; alert(styleString); var computedStyle = getComputedStyle(pgraph); var computedStyleString = "Computed Styles\n"; computedStyleString += 'color: ' + computedStyle.color + "\n"; computedStyleString += 'margin: ' + computedStyle.margin + "\n"; computedStyleString += 'padding: ' + computedStyle.padding + "\n"; computedStyleString += 'border: ' + computedStyle.borderBottom + "\n"; computedStyleString += 'width: ' + computedStyle.width + "\n"; alert(computedStyleString); return false; }); document.getElementById("setstyles").addEventListener("click", function() { var pgraph = document.getElementById("pgraph"); pgraph.style.borderBottom = 'none'; pgraph.style.fontStyle = 'normal'; pgraph.style.width = 'auto'; pgraph.style.padding = 'auto'; pgraph.style.margin = 'auto'; return false; }); } </script> <style> #pgraph { border-bottom:2px solid blue; width:80%; padding:10px; } </style> </head> <body> <h1>Styles</h1> <p id="pgraph" style="margin:10px auto 30px auto">This is a paragraph</p> <button id="getstyles">Get Styles</button> <button id="setstyles">Set Styles</button> </body> </html>
The paragraph, with id
pgraph
, has CSS styles set in three different ways: inline (margin
), in the head
of the page (border-bottom
, width
, and padding
), and from an external stylesheet customstyles.css (font-size
, color
, and font-style
).
Clicking the "Get Styles" button invokes a handler which pops up two JavaScript alerts. The first lists the styles retrieved pgraph.style
; note that color
, padding
, border
, and width
are all blank. The second alert, however, displays style information retrieved from getComputedStyle(pgraph)
; note that all of the style information - regardless of whether it was added inline, in the head
of the page, or from the external stylesheet, is displayed.
The "Set Styles" button, when clicked, changes the styles of the paragraph. Check out how the two methods of getting the styles differ when you click "Get Styles" after setting the styles.
Elements can be hidden and shown by changing their visibility
or display
values. The visibility
style can be set to visible
or hidden
and the display
property can be set to block
, table-row
, none
, and several other values. The two work slightly differently as the following example illustrates:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Showing and Hiding Elements with JavaScript</title> <link href="visibility.css" rel="stylesheet"> <script> function changeVisibility(id){ var elem = document.getElementById(id); var visibility; if (elem.style.visibility == "hidden") { elem.style.visibility = "visible"; } else { elem.style.visibility = "hidden"; } var computedStyle = getComputedStyle(elem,null); visibility = computedStyle["visibility"]; msg("The <em>visibility</em> of row <em>" + id + "</em> is <em>" + visibility + "</em>."); } function changeDisplay(id){ var elem = document.getElementById(id); var display; if (elem.style.display == "none") { elem.style.display = ""; } else { elem.style.display = "none"; } var computedStyle = getComputedStyle(elem,null); display = computedStyle["display"]; msg("The <em>display</em> of row <em>" + id + "</em> is <em>" + display + "</em>."); } function msg(text) { document.getElementById("msg").innerHTML = text; } </script> </head> <body> <h1>Hiding and Showing Elements</h1> <table> <tr id="tr1"><td>Row 1</td></tr> <tr id="tr2"><td>Row 2</td></tr> <tr id="tr3"><td>Row 3</td></tr> <tr id="tr4"><td>Row 4</td></tr> </table> <div id="msg">Style messages</div> <h2>visibility</h2> <button onclick="changeVisibility('tr1')">Row 1</button> <button onclick="changeVisibility('tr2')">Row 2</button> <button onclick="changeVisibility('tr3')">Row 3</button> <button onclick="changeVisibility('tr4')">Row 4</button> <h2>display</h2> <button onclick="changeDisplay('tr1')">Row 1</button> <button onclick="changeDisplay('tr2')">Row 2</button> <button onclick="changeDisplay('tr3')">Row 3</button> <button onclick="changeDisplay('tr4')">Row 4</button> </body> </html>
This page has two functions: changeVisibility()
and changeDisplay()
. The changeVisibility()
function checks the value of the visibility
style of the passed element and changes it to its opposite. The changeDisplay()
function does the same with the display
style. The functions are called with buttons on the page and are passed in ids of table rows from the table on the page.
The main difference between setting visibility
to hidden
and setting display
to none
is that setting visibility
to hidden
does not modify the layout of the page; it simply hides the element. Setting display
to none
, on the other hand, collapses the element, so that the surrounding relatively positioned elements re-position themselves.
Check out the screenshot below:
Row 1 has visibility
set to hidden
, so you can see the space for the row, but you cannot see the row itself. Row 3 has display
set to none
so it's as if the row was not even there.
In this exercise, you will modify a Math Quiz to only show the countdown timer when it is running.
resetTimer()
and questionChanged()
.Only show the Answer row when a question is selected.
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Math Quiz</title> <link href="MathQuiz.css" rel="stylesheet"> <script src="questions.js"></script> <script> var timer, timePerQuestion = 10; window.onload = function() { init(); } function init() { var category = document.getElementById("category"); var question = document.getElementById("question"); var btnCheck = document.getElementById("btnCheck"); var timeLeft = document.getElementById("timeLeft"); category.addEventListener('change', function() { selChanged(category,categories,question); resetTimer(timePerQuestion); }); question.addEventListener('change', function() { questionChanged(); }); btnCheck.addEventListener('click', function() { checkAnswer(); }); timeLeft.addEventListener('focus', function() { timeLeft.blur(); }); selChanged(category,categories,question); resetTimer(timePerQuestion); } function selChanged(sel,data,dependentSel) { var selection = sel.options[sel.selectedIndex].value; var arrOptions = data[selection]; var opt; dependentSel.options.length = 1; for (var i in arrOptions) { opt = new Option(arrOptions[i].q,arrOptions[i].a); dependentSel.add(opt); } } function resetTimer(seconds) { var timerRow = document.getElementById("timerRow"); timerRow.style.display = "none"; document.getElementById("timeLeft").value = seconds; clearInterval(timer); } function decrementTimer() { var timeLeft = document.getElementById("timeLeft"); timeLeft.value--; if (timeLeft.value < 0) { resetTimer(timePerQuestion); msg("Time's up! The answer is " + getAnswer() + "."); removeOption(); } } function checkAnswer() { var userAnswer = document.getElementById("answer").value; var correctAnswer = getAnswer(); if (userAnswer === correctAnswer) { msg("Right! The answer is " + correctAnswer + "."); } else { msg("Sorry. The correct answer is " + correctAnswer + "."); } removeOption(); questionChanged(); } function getAnswer() { var i = document.Quiz.question.selectedIndex; var answer = document.Quiz.question[i].value; return answer; } function removeOption() { var category = document.Quiz.category; var question = document.Quiz.question; question.remove(question.selectedIndex); if(question.options.length == 1) { category.remove(category.selectedIndex); if (category.options.length == 0) { endQuiz(); } else { selChanged(category,categories,question); } } resetTimer(timePerQuestion); } function questionChanged() { document.Quiz.answer.value=""; var timerRow; if (document.Quiz.question.selectedIndex === 0) { document.Quiz.btnCheck.disabled = true; document.Quiz.answer.disabled = true; resetTimer(timePerQuestion); } else { document.Quiz.btnCheck.disabled = false; document.Quiz.answer.disabled = false; document.Quiz.answer.focus(); timer = setInterval(decrementTimer,1000); timerRow = document.getElementById("timerRow"); timerRow.style.display = ""; } } function endQuiz() { var category = document.Quiz.category; var question = document.Quiz.question; resetTimer(timePerQuestion); alert("Thanks for playing! The quiz will now reload."); category.add(new Option("Addition","addition")); category.add(new Option("Subtraction","subtraction")); category.add(new Option("Multiplication","multiplication")); category.add(new Option("Division","division")); selChanged(category,categories,question); resetTimer(timePerQuestion); } function msg(text) { document.getElementById("msg").innerHTML = text; } </script> </head> <body> <form name="Quiz" onsubmit="return false;"> <table> <tr> <td>Category:</td> <td> <select name="category" id="category"> <option value="addition">Addition</option> <option value="subtraction">Subtraction</option> <option value="multiplication">Multiplication</option> <option value="division">Division</option> </select> </td> </tr> <tr> <td>Question:</td> <td> <select name="question" id="question"> <option value="0">--Please Choose--</option> </select> </td> </tr> <tr> <td>Answer:</td> <td> <input type="text" name="answer" id="answer" size="2" disabled="disabled"> <input type="button" name="btnCheck" id="btnCheck" value="Check Answer" disabled="disabled"> </td> </tr> <tr id="timerRow"> <td>Timer:</td> <td><input type="text" name="timeLeft" id="timeLeft" size="2"> seconds left</td> </tr> <tr> <td id="msg" colspan="2">Good luck!</td> </tr> </table> </form> </body> </html>
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Math Quiz</title> <link href="MathQuiz.css" rel="stylesheet"> <script src="questions.js"></script> <script> var timer, timePerQuestion=10; window.onload = function() { init(); } function init() { var category = document.getElementById("category"); var question = document.getElementById("question"); var btnCheck = document.getElementById("btnCheck"); var timeLeft = document.getElementById("timeLeft"); category.addEventListener('change', function() { selChanged(category,categories,question); resetTimer(timePerQuestion); }); question.addEventListener('change', function() { questionChanged(); }); btnCheck.addEventListener('click', function() { checkAnswer(); }); timeLeft.addEventListener('focus', function() { timeLeft.blur(); }); selChanged(category,categories,question); resetTimer(timePerQuestion); } function selChanged(sel,data,dependentSel) { var selection = sel.options[sel.selectedIndex].value; var arrOptions = data[selection]; var opt; dependentSel.options.length = 1; for (var i in arrOptions) { opt = new Option(arrOptions[i].q,arrOptions[i].a); dependentSel.add(opt); } } function resetTimer(seconds) { var timerRow = document.getElementById("timerRow"); var answerRow = document.getElementById("answerRow"); timerRow.style.display = "none"; answerRow.style.display = "none"; document.getElementById("timeLeft").value = seconds; clearInterval(timer); } function decrementTimer() { var timeLeft = document.getElementById("timeLeft"); timeLeft.value--; if (timeLeft.value < 0) { resetTimer(timePerQuestion); msg("Time's up! The answer is " + getAnswer() + "."); removeOption(); } } function checkAnswer() { var userAnswer = document.getElementById("answer").value; var correctAnswer = getAnswer(); if (userAnswer === correctAnswer) { msg("Right! The answer is " + correctAnswer + "."); } else { msg("Sorry. The correct answer is " + correctAnswer + "."); } removeOption(); questionChanged(); } function getAnswer() { var i = document.Quiz.question.selectedIndex; var answer = document.Quiz.question[i].value; return answer; } function removeOption() { var category = document.Quiz.category; var question = document.Quiz.question; question.remove(question.selectedIndex); if(question.options.length == 1) { category.remove(category.selectedIndex); if (category.options.length == 0) { endQuiz(); } else { selChanged(category,categories,question); } } resetTimer(timePerQuestion); } function questionChanged() { document.Quiz.answer.value=""; var timerRow,answerRow; if (document.Quiz.question.selectedIndex === 0) { document.Quiz.btnCheck.disabled = true; document.Quiz.answer.disabled = true; resetTimer(timePerQuestion); } else { document.Quiz.btnCheck.disabled = false; document.Quiz.answer.disabled = false; timer = setInterval(decrementTimer,1000); timerRow = document.getElementById("timerRow"); timerRow.style.display = ""; answerRow = document.getElementById("answerRow"); answerRow.style.display = ""; document.Quiz.answer.focus(); } } function endQuiz() { var category = document.Quiz.category; var question = document.Quiz.question; resetTimer(timePerQuestion); alert("Thanks for playing! The quiz will now reload."); category.add(new Option("Addition","addition")); category.add(new Option("Subtraction","subtraction")); category.add(new Option("Multiplication","multiplication")); category.add(new Option("Division","division")); selChanged(category,categories,question); resetTimer(timePerQuestion); } function msg(text) { document.getElementById("msg").innerHTML = text; } </script> </head> <body> <form name="Quiz" onsubmit="return false;"> <table> <tr> <td>Category:</td> <td> <select name="category" id="category"> <option value="addition">Addition</option> <option value="subtraction">Subtraction</option> <option value="multiplication">Multiplication</option> <option value="division">Division</option> </select> </td> </tr> <tr> <td>Question:</td> <td> <select name="question" id="question"> <option value="0">--Please Choose--</option> </select> </td> </tr> <tr id="answerRow"> <td>Answer:</td> <td> <input type="text" name="answer" id="answer" size="2" disabled="disabled"> <input type="button" name="btnCheck" id="btnCheck" value="Check Answer" disabled="disabled"> </td> </tr> <tr id="timerRow"> <td>Timer:</td> <td><input type="text" name="timeLeft" id="timeLeft" size="2"> seconds left</td> </tr> <tr> <td id="msg" colspan="2">Good luck!</td> </tr> </table> </form> </body> </html>
HTML tables can be created and manipulated dynamically with JavaScript. Each table
element contains a rows
array and methods for inserting and deleting rows: insertRow()
and deleteRow()
. Each tr
element contains a cells
array and methods for inserting and deleting cells: insertCell()
and deleteCell()
. The following example shows how these objects can be used to dynamically create HTML tables:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Manipulating Tables</title> <link href="table.css" rel="stylesheet"> <script> function addRow(tableId, cells){ var tableElem = document.getElementById(tableId); var newRow = tableElem.insertRow(tableElem.rows.length); var newCell; for (var i=0; i < cells.length; i++) { newCell = newRow.insertCell(newRow.cells.length); newCell.innerHTML = cells[i]; } return newRow; } function deleteRow(tableId, rowNumber){ var tableElem = document.getElementById(tableId); if (rowNumber > 0 && rowNumber < tableElem.rows.length) { tableElem.deleteRow(rowNumber); } else { alert("Failed"); } } window.onload = function() { var btnAdd = document.getElementById("btnAdd"); var btnDelete = document.getElementById("btnDelete"); btnAdd.addEventListener('click', function() { var cells = [btnAdd.form.FirstName.value,btnAdd.form.LastName.value]; addRow('tblPeople', cells); }); btnDelete.addEventListener('click', function() { deleteRow('tblPeople', btnDelete.form.RowNum.value) }); }; </script> </head> <body> <table id="tblPeople"> <tr> <th>First Name</th> <th>Last Name</th> </tr> </table> <hr> <form name="formName"> <label for="FirstName">First Name:</label> <input type="text" name="FirstName"><br> <label for="LastName">Last Name:</label> <input type="text" name="LastName"><br> <input type="button" id="btnAdd" value="Add Name"> <hr> <label for="RowNum">Remove Row:</label> <input type="text" size="1" name="RowNum"> <input type="button" id="btnDelete" value="Delete Row"> </form> </body> </html>
The body of the page contains a table with an id
of tblPeople
. The table contains a single row of headers.
<table id="tblPeople"> <tr> <th>First Name</th> <th>Last Name</th> </tr> </table>
Below the table is a form that allows the user to enter a first and last name. When the "Add Name" button is clicked, the addRow()
function is called and passed in the id
of the table (tblPeople
) and a new array containing the user-entered values:
var cells = [btnAdd.form.FirstName.value, btnAdd.form.LastName.value]; addRow('tblPeople', cells);
The addRow()
function uses the insertRow()
method of the table
to add a new row at the end of the table and then loops through the passed-in array, creating and populating one cell for each item. The function also returns the new row. Although the returned value isn't used in this example, it can be useful if you then want to manipulate the new row further.
function addRow(tableId, cells){ var tableElem = document.getElementById(tableId); var newRow = tableElem.insertRow(tableElem.rows.length); var newCell; for (var i=0; i < cells.length; i++) { newCell = newRow.insertCell(newRow.cells.length); newCell.innerHTML = cells[i]; } return newRow; }
The form also contains a "Delete Row" button that, when clicked, passes the id
of the table (tblPeople
) and the number entered by the user in the RowNum
text field.
deleteRow('tblPeople', btnDelete.form.RowNum.value)
The deleteRow()
function checks to see if the row specified exists and is not the first row (row 0, which is the header row). If both conditions are true, it deletes the row. Otherwise, it alerts "Failed".
function deleteRow(tableId, rowNumber){ var tableElem = document.getElementById(tableId); if (rowNumber > 0 && rowNumber < tableElem.rows.length) { tableElem.deleteRow(rowNumber); } else { alert("Failed"); } }
In this exercise, you will dynamically create a table that shows the user how she is doing on the Math Quiz. The screenshot below shows how the result will look:
msg()
function so that it takes a second argument: color
, and uses it to change the text of the "msg" div
to the passed-in color.msg()
to pass in a color
as well as the text
: green if the answer is correct and red if it is not.Option
objects have a text
property that holds the displayed text of the option. Add a getQuestion()
function that returns the text of the selected question.id
of tblResults
.checkAnswer()
function so that it adds a new row to the results table showing the question, user's answer, and correct answer.Modify the code so that the new row's background color is #00ff00 if the answer is correct and #ff9999 if it is not. Hint: the addRow()
function returns the newly added row.
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Math Quiz</title> <link href="MathQuiz.css" rel="stylesheet"> <script src="questions.js"></script> <script> var timer, timePerQuestion = 10; window.onload = function() { init(); } function init() { var category = document.getElementById("category"); var question = document.getElementById("question"); var btnCheck = document.getElementById("btnCheck"); var timeLeft = document.getElementById("timeLeft"); category.addEventListener('change', function() { selChanged(category,categories,question); resetTimer(timePerQuestion); }); question.addEventListener('change', function() { questionChanged(); }); btnCheck.addEventListener('click', function() { checkAnswer(); }); timeLeft.addEventListener('focus', function() { timeLeft.blur(); }); selChanged(category,categories,question); resetTimer(timePerQuestion); } function selChanged(sel,data,dependentSel) { var selection = sel.options[sel.selectedIndex].value; var arrOptions = data[selection]; var opt; dependentSel.options.length = 1; for (var i in arrOptions) { opt = new Option(arrOptions[i].q,arrOptions[i].a); dependentSel.add(opt); } } function resetTimer(seconds) { var timerRow = document.getElementById("timerRow"); var answerRow = document.getElementById("answerRow"); timerRow.style.display = "none"; answerRow.style.display = "none"; document.getElementById("timeLeft").value = seconds; clearInterval(timer); } function decrementTimer() { var timeLeft = document.getElementById("timeLeft"); timeLeft.value--; if (timeLeft.value < 0) { resetTimer(timePerQuestion); msg("Time's up! The answer is " + getAnswer() + ".","red"); removeOption(); } } function addRow(tableId, cells) { var tableElem = document.getElementById(tableId); var newRow = tableElem.insertRow(tableElem.rows.length); var newCell; for (var i = 0; i < cells.length; i++) { newCell = newRow.insertCell(newRow.cells.length); newCell.innerHTML = cells[i]; } return newRow; } function checkAnswer() { var userAnswer = document.getElementById("answer").value; var correctAnswer = getAnswer(); var question = getQuestion(); var arrCells = [question, userAnswer, correctAnswer]; addRow("tblResults", arrCells); if (userAnswer === correctAnswer) { msg("Right! The answer is " + correctAnswer + ".","green"); } else { msg("Sorry. The correct answer is " + correctAnswer + ".","red"); } removeOption(); questionChanged(); } function getAnswer() { var i = document.Quiz.question.selectedIndex; var answer = document.Quiz.question[i].value; return answer; } function getQuestion(){ var i = document.Quiz.question.selectedIndex; var question = document.Quiz.question[i].text; return question; } function removeOption() { var category = document.Quiz.category; var question = document.Quiz.question; question.remove(question.selectedIndex); if(question.options.length == 1) { category.remove(category.selectedIndex); if (category.options.length == 0) { endQuiz(); } else { selChanged(category,categories,question); } } resetTimer(timePerQuestion); } function questionChanged() { document.Quiz.answer.value = ""; var timerRow,answerRow; if (document.Quiz.question.selectedIndex === 0) { document.Quiz.btnCheck.disabled = true; document.Quiz.answer.disabled = true; resetTimer(timePerQuestion); } else { document.Quiz.btnCheck.disabled = false; document.Quiz.answer.disabled = false; timer = setInterval(decrementTimer,1000); timerRow = document.getElementById("timerRow"); timerRow.style.display = ""; answerRow = document.getElementById("answerRow"); answerRow.style.display = ""; document.Quiz.answer.focus(); } } function endQuiz() { var category = document.Quiz.category; var question = document.Quiz.question; resetTimer(timePerQuestion); alert("Thanks for playing! The quiz will now reload."); category.add(new Option("Addition","addition")); category.add(new Option("Subtraction","subtraction")); category.add(new Option("Multiplication","multiplication")); category.add(new Option("Division","division")); selChanged(category,categories,question); resetTimer(timePerQuestion); } function msg(text, color) { document.getElementById("msg").innerHTML = text; document.getElementById("msg").style.color = color; } </script> </head> <body> <form name="Quiz" onsubmit="return false;"> <table> <tr> <td>Category:</td> <td> <select name="category" id="category"> <option value="addition">Addition</option> <option value="subtraction">Subtraction</option> <option value="multiplication">Multiplication</option> <option value="division">Division</option> </select> </td> </tr> <tr> <td>Question:</td> <td> <select name="question" id="question"> <option value="0">--Please Choose--</option> </select> </td> </tr> <tr id="answerRow"> <td>Answer:</td> <td> <input type="text" name="answer" id="answer" size="2" disabled="disabled"> <input type="button" name="btnCheck" id="btnCheck" value="Check Answer" disabled="disabled"> </td> </tr> <tr id="timerRow"> <td>Timer:</td> <td><input type="text" name="timeLeft" id="timeLeft" size="2"> seconds left</td> </tr> <tr> <td id="msg" colspan="2">Good luck!</td> </tr> </table> </form> <hr> <table id="tblResults"> <tr> <th>Question</th> <th>Your answer</th> <th>Correct answer</th> </tr> </table> </body> </html>
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Math Quiz</title> <link href="MathQuiz.css" rel="stylesheet"> <script src="questions.js"></script> <script> var timer, timePerQuestion = 10; window.onload = function() { init(); } function init() { var category = document.getElementById("category"); var question = document.getElementById("question"); var btnCheck = document.getElementById("btnCheck"); var timeLeft = document.getElementById("timeLeft"); category.addEventListener('change', function() { selChanged(category,categories,question); resetTimer(timePerQuestion); }); question.addEventListener('change', function() { questionChanged(); }); btnCheck.addEventListener('click', function() { checkAnswer(); }); timeLeft.addEventListener('focus', function() { timeLeft.blur(); }); selChanged(category,categories,question); resetTimer(timePerQuestion); } function selChanged(sel,data,dependentSel) { var selection = sel.options[sel.selectedIndex].value; var arrOptions = data[selection]; var opt; dependentSel.options.length = 1; for (var i in arrOptions) { opt = new Option(arrOptions[i].q,arrOptions[i].a); dependentSel.add(opt); } } function resetTimer(seconds) { var timerRow = document.getElementById("timerRow"); var answerRow = document.getElementById("answerRow"); timerRow.style.display = "none"; answerRow.style.display = "none"; document.getElementById("timeLeft").value = seconds; clearInterval(timer); } function decrementTimer() { var timeLeft = document.getElementById("timeLeft"); timeLeft.value--; if (timeLeft.value < 0) { resetTimer(timePerQuestion); msg("Time's up! The answer is " + getAnswer() + ".","red"); removeOption(); } } function addRow(tableId, cells) { var tableElem = document.getElementById(tableId); var newRow = tableElem.insertRow(tableElem.rows.length); var newCell; for (var i = 0; i < cells.length; i++) { newCell = newRow.insertCell(newRow.cells.length); newCell.innerHTML = cells[i]; } return newRow; } function checkAnswer() { var userAnswer = document.getElementById("answer").value; var correctAnswer = getAnswer(); var question = getQuestion(); var arrCells = [question, userAnswer, correctAnswer]; var row = addRow("tblResults", arrCells); if (userAnswer === correctAnswer) { msg("Right! The answer is " + correctAnswer + ".","green"); row.style.backgroundColor="#00ff00"; } else { msg("Sorry. The correct answer is " + correctAnswer + ".","red"); row.style.backgroundColor="#ff9999"; } removeOption(); questionChanged(); } function getAnswer() { var i = document.Quiz.question.selectedIndex; var answer = document.Quiz.question[i].value; return answer; } function getQuestion(){ var i = document.Quiz.question.selectedIndex; var question = document.Quiz.question[i].text; return question; } function removeOption() { var category = document.Quiz.category; var question = document.Quiz.question; question.remove(question.selectedIndex); if(question.options.length == 1) { category.remove(category.selectedIndex); if (category.options.length == 0) { endQuiz(); } else { selChanged(category,categories,question); } } resetTimer(timePerQuestion); } function questionChanged() { document.Quiz.answer.value = ""; var timerRow,answerRow; if (document.Quiz.question.selectedIndex === 0) { document.Quiz.btnCheck.disabled = true; document.Quiz.answer.disabled = true; resetTimer(timePerQuestion); } else { document.Quiz.btnCheck.disabled = false; document.Quiz.answer.disabled = false; timer = setInterval(decrementTimer,1000); timerRow = document.getElementById("timerRow"); timerRow.style.display = ""; answerRow = document.getElementById("answerRow"); answerRow.style.display = ""; document.Quiz.answer.focus(); } } function endQuiz() { var category = document.Quiz.category; var question = document.Quiz.question; resetTimer(timePerQuestion); alert("Thanks for playing! The quiz will now reload."); category.add(new Option("Addition","addition")); category.add(new Option("Subtraction","subtraction")); category.add(new Option("Multiplication","multiplication")); category.add(new Option("Division","division")); selChanged(category,categories,question); resetTimer(timePerQuestion); } function msg(text, color) { document.getElementById("msg").innerHTML = text; document.getElementById("msg").style.color = color; } </script> </head> <body> <form name="Quiz" onsubmit="return false;"> <table> <tr> <td>Category:</td> <td> <select name="category" id="category"> <option value="addition">Addition</option> <option value="subtraction">Subtraction</option> <option value="multiplication">Multiplication</option> <option value="division">Division</option> </select> </td> </tr> <tr> <td>Question:</td> <td> <select name="question" id="question"> <option value="0">--Please Choose--</option> </select> </td> </tr> <tr id="answerRow"> <td>Answer:</td> <td> <input type="text" name="answer" id="answer" size="2" disabled="disabled"> <input type="button" name="btnCheck" id="btnCheck" value="Check Answer" disabled="disabled"> </td> </tr> <tr id="timerRow"> <td>Timer:</td> <td><input type="text" name="timeLeft" id="timeLeft" size="2"> seconds left</td> </tr> <tr> <td id="msg" colspan="2">Good luck!</td></tr> </tr> </table> </form> <hr> <table id="tblResults"> <tr> <th>Question</th> <th>Your answer</th> <th>Correct answer</th> </tr> </table> </body> </html>
The dimensions of an object can be changed by modifying the width
and height
properties of the element's style
property. The following example demonstrates this:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Dimensions</title> <link href="dimensions.css" rel="stylesheet"> <script> function grow(elem){ var curWidth = parseInt(getComputedStyle(elem).getPropertyValue("width")); var curHeight = parseInt(getComputedStyle(elem).getPropertyValue("height")); elem.style.width = (curWidth * 1.5) + 'px'; elem.style.height = (curHeight * 1.5) + 'px'; showDimensions(elem); } function shrink(elem){ var curWidth = parseInt(getComputedStyle(elem).getPropertyValue("width")); var curHeight = parseInt(getComputedStyle(elem).getPropertyValue("height")); elem.style.width = (curWidth / 1.5) + 'px'; elem.style.height = (curHeight / 1.5) + 'px'; showDimensions(elem); } function showDimensions(elem) { elem.innerHTML = "w: " + getComputedStyle(elem).getPropertyValue("width") + "<br>h: " + getComputedStyle(elem).getPropertyValue("height"); } window.onload = function() { var block = document.getElementById("divBlock"); block.addEventListener('mouseover', function() { grow(block); }) block.addEventListener('mouseout', function() { shrink(block); }) showDimensions(block); }; </script> </head> <body> <div id="divBlock"></div> </body> </html>
When the page loads, we begin observing mouseover
and mouseout
events on the block div
. We call grow()
on mouse overs and shrink()
on mouse outs.
The grow()
function uses parseInt()
to cut off the units (e.g., px) from the value of the width
and height
of the div
and assigns the resulting integers to variables: curWidth
and curHeight
. It then modifies the width
and height
properties of the element by multiplying the current values by 1.5.
The shrink()
function does the same thing, but it divides by 1.5 instead of multiplying.
The example below shows how a timed slider can be created by dynamically changing an element's dimensions:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Slider</title> <link href="slider.css" rel="stylesheet"> <script> var timer, timesUp; function resetTimer() { var slider = document.getElementById("divSlider"); timesUp = true; slider.style.width = "0px"; clearInterval(timer); } function decrementTimer() { var slider = document.getElementById("divSlider"); var curWidth = parseInt(getComputedStyle(slider).getPropertyValue("width")); timesUp = false; if (curWidth < 200) { slider.style.width = curWidth + 2 + "px"; } else { alert("Time's up!"); resetTimer(); } } window.onload = function() { var btnStart = document.getElementById("btnStart"); resetTimer(); btnStart.addEventListener('click', function() { timer = setInterval(decrementTimer, 100); }); }; </script> </head> <body> <div id="divSliderBG"> <div id="divSlider"></div> </div> <button id="btnStart">Start Timer</button> </body> </html>
The position of an object can be changed by modifying the left
and top
properties of the element's style
property. The following example demonstrates this:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Position</title> <link href="position.css" rel="stylesheet"> <script> function moveH(elem, distance){ var curLeft = parseInt(getComputedStyle(elem).getPropertyValue("left")); elem.style.left = (curLeft + distance) + "px"; } function moveV(elem, distance){ var curTop = parseInt(getComputedStyle(elem).getPropertyValue("top")); elem.style.top = (curTop + distance) + "px"; } window.onload = function() { var btnLeft = document.getElementById("btnLeft"); var btnRight = document.getElementById("btnRight"); var btnUp = document.getElementById("btnUp"); var btnDown = document.getElementById("btnDown"); var block = document.getElementById("divBlock"); btnLeft.addEventListener('click', function() { moveH(block,-10); }); btnRight.addEventListener('click', function() { moveH(block,10); }); btnUp.addEventListener('click', function() { moveV(block,-10); }); btnDown.addEventListener('click', function() { moveV(block,10); }); }; </script> </head> <body> <div id="field"> <button id="btnLeft">Left</button> <button id="btnRight">Right</button> <button id="btnUp">Up</button> <button id="btnDown">Down</button> <div id="divBlock"></div> </div> </body> </html>
When the page loads, we begin observing click
events on the buttons to call moveH()
and moveV()
.
The moveH()
function uses parseInt()
to cut off the units (e.g., px) from the value of the left
property and assigns the resulting integers to the curLeft
variable. It then adds the passed-in distance
to the left
property.
The moveV()
function does the same thing, but it modifies the top
property rather than the left
property.
The example below shows how a different type of timed slider can be created by dynamically changing an element's position:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Slider</title> <link href="slider2.css" rel="stylesheet"> <script> var timer, timesUp; function resetTimer(){ var slider = document.getElementById("divSlider"); timesUp = true; slider.style.left = "1px"; clearInterval(timer); } function decrementTimer(){ var slider = document.getElementById("divSlider"); var curLeft = parseInt(getComputedStyle(slider).getPropertyValue("left")); var curWidth = parseInt(getComputedStyle(slider).getPropertyValue("width")); timesUp = false; if (curLeft < 198 - curWidth) { slider.style.left = curLeft + 2 + "px"; } else { alert("Time's up!"); resetTimer(); } } window.onload = function() { var btnStart = document.getElementById("btnStart"); resetTimer(); btnStart.addEventListener('click', function() { timer = setInterval(decrementTimer, 100); }); }; </script> </head> <body> <div id="divSliderBG"> <div id="divSlider"></div> </div> <button id="btnStart">Start Timer</button> </body> </html>
In this exercise, you will modify the Math Quiz so that the timer is a slider rather than a count down. The result will look like this:
input
element to two div
s.<tr id="timerRow"> <td>Timer:</td> <td> <div id="divSliderBG"> <div id="divSlider"></div> </div> </td> </tr>
timeLeft
input
have been removed and the code within the decrementTimer()
function has been commented out.decrementTimer()
function to use a slider like the one shown in the screenshot above.resetTimer()
function so that it sets the left
style of the divSlider
back to "1px".<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Math Quiz</title> <link href="MathQuiz.css" rel="stylesheet"> <script src="questions.js"></script> <script> var timer, timePerQuestion = 10; window.onload = function() { init(); } function init() { var category = document.getElementById("category"); var question = document.getElementById("question"); var btnCheck = document.getElementById("btnCheck"); category.addEventListener('change', function() { selChanged(category,categories,question); resetTimer(timePerQuestion); }); question.addEventListener('change', function() { questionChanged(); }); btnCheck.addEventListener('click', function() { checkAnswer(); }); selChanged(category,categories,question); resetTimer(timePerQuestion); } function selChanged(sel,data,dependentSel) { var selection = sel.options[sel.selectedIndex].value; var arrOptions = data[selection]; var opt; dependentSel.options.length = 1; for (var i in arrOptions) { opt = new Option(arrOptions[i].q,arrOptions[i].a); dependentSel.add(opt); } } function resetTimer(seconds) { var slider = document.getElementById("divSlider"); var timerRow = document.getElementById("timerRow"); var answerRow = document.getElementById("answerRow"); slider.style.left = "1px"; timerRow.style.display = "none"; answerRow.style.display = "none"; clearInterval(timer); } function decrementTimer() { var slider = document.getElementById("divSlider"); var curLeft = parseInt(getComputedStyle(slider).getPropertyValue("left")); var curWidth = parseInt(getComputedStyle(slider).getPropertyValue("width")); if (curLeft < 198 - curWidth) { slider.style.left = curLeft + 2 + "px"; } else { resetTimer(timePerQuestion); msg("Time's up! The answer is " + getAnswer() + ".","red"); removeOption(); } } function addRow(tableId, cells){ var tableElem = document.getElementById(tableId); var newRow = tableElem.insertRow(tableElem.rows.length); var newCell; for (var i = 0; i < cells.length; i++) { newCell = newRow.insertCell(newRow.cells.length); newCell.innerHTML = cells[i]; } return newRow; } function checkAnswer() { var userAnswer = document.getElementById("answer").value; var correctAnswer = getAnswer(); var question = getQuestion(); var arrCells = [question, userAnswer, correctAnswer]; var row = addRow("tblResults", arrCells); if (userAnswer === correctAnswer) { msg("Right! The answer is " + correctAnswer + ".","green"); row.style.backgroundColor="#00ff00"; } else { msg("Sorry. The correct answer is " + correctAnswer + ".","red"); row.style.backgroundColor="#ff9999"; } removeOption(); questionChanged(); } function getAnswer() { var i = document.Quiz.question.selectedIndex; var answer = document.Quiz.question[i].value; return answer; } function getQuestion(){ var i = document.Quiz.question.selectedIndex; var question = document.Quiz.question[i].text; return question; } function removeOption() { var category = document.Quiz.category; var question = document.Quiz.question; question.remove(question.selectedIndex); if(question.options.length == 1) { category.remove(category.selectedIndex); if (category.options.length == 0) { endQuiz(); } else { selChanged(category,categories,question); } } resetTimer(timePerQuestion); } function questionChanged() { document.Quiz.answer.value = ""; var timerRow,answerRow; if (document.Quiz.question.selectedIndex === 0) { document.Quiz.btnCheck.disabled = true; document.Quiz.answer.disabled = true; resetTimer(timePerQuestion); } else { document.Quiz.btnCheck.disabled = false; document.Quiz.answer.disabled = false; timer = setInterval(decrementTimer,100); timerRow = document.getElementById("timerRow"); timerRow.style.display = ""; answerRow = document.getElementById("answerRow"); answerRow.style.display = ""; document.Quiz.answer.focus(); } } function endQuiz() { var category = document.Quiz.category; var question = document.Quiz.question; resetTimer(timePerQuestion); alert("Thanks for playing! The quiz will now reload."); category.add(new Option("Addition","addition")); category.add(new Option("Subtraction","subtraction")); category.add(new Option("Multiplication","multiplication")); category.add(new Option("Division","division")); selChanged(category,categories,question); resetTimer(timePerQuestion); } function msg(text, color) { document.getElementById("msg").innerHTML = text; document.getElementById("msg").style.color = color; } </script> </head> <body> <form name="Quiz" onsubmit="return false;"> <table> <tr> <td>Category:</td> <td> <select name="category" id="category"> <option value="addition">Addition</option> <option value="subtraction">Subtraction</option> <option value="multiplication">Multiplication</option> <option value="division">Division</option> </select> </td> </tr> <tr> <td>Question:</td> <td> <select name="question" id="question"> <option value="0">--Please Choose--</option> </select> </td> </tr> <tr id="answerRow"> <td>Answer:</td> <td> <input type="text" name="answer" id="answer" size="2" disabled="disabled"> <input type="button" name="btnCheck" id="btnCheck" value="Check Answer" disabled="disabled"> </td> </tr> <tr id="timerRow"> <td>Timer:</td> <td> <div id="divSliderBG"> <div id="divSlider"></div> </div> </td> </tr> <tr> <td id="msg" colspan="2">Good luck!</td> </tr> </table> </form> <hr> <table id="tblResults"> <tr> <th>Question</th> <th>Your answer</th> <th>Correct answer</th> </tr> </table> </body> </html>
The z-index
value of an element indicates its relative position in the "stack" of elements on the page. Elements with higher z-index values sit on top of elements with lower values. You can think of a stack of papers thrown on a table. The ones at the top have a higher z-index than the ones on the bottom. In the screenshot below, the blue box has a higher z-index than the red box:
The z-index
of an object can be changed by modifying the zIndex
property of the element's style
property. The following example demonstrates this:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>zIndex</title> <link href="zindex.css" rel="stylesheet"> <script> var z = 0; function changeZ(elem){ z += 10; elem.style.zIndex = z; elem.innerHTML = "z: " + z; } window.onload = function() { var divRed = document.getElementById("divRed"); var divBlue = document.getElementById("divBlue"); divRed.addEventListener('click', function() { changeZ(divRed); }); divBlue.addEventListener('click', function() { changeZ(divBlue); }); }; </script> </head> <body> <div id="divRed"></div> <div id="divBlue"></div> </body> </html>
The variable z
always holds the highest z-index. The function changeZ()
simply adds 10 to z
and assigns the resulting value to the zIndex
property of the passed in object.
function changeZ(elem){ z += 10; elem.style.zIndex = z; elem.innerHTML = "z: " + z; }
Behind all of our work manipulating and reading CSS styles with JavaScript lies the CSS Object Model API, a complete (and ever changing) specification from the W3C that defines how to control CSS with JavaScript. The complete specification is at https://www.w3.org/TR/cssom/; you may also find useful the Mozilla Developer Networ's CSS Object Model documentation.
While delving too deeply into the API itself is beyond the scope of this course, we will take a quick look at a way in which we can check to see if a user's browser offers support for a given CSS property and value. Consider the following example:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Supports</title> <script> window.onload = function() { document.getElementById("checkit").addEventListener("click", function() { var p = document.getElementById("p").value; var v = document.getElementById("v").value; if (CSS.supports(p, v)) { alert('Your browser DOES support property ' + p + ' with value ' + v); } else { alert('Your browser does NOT support property ' + p + ' with value ' + v); } return false; }); } </script> </head> <body> <h1>Supports</h1> <form action="#"> <input type="text" id="p" placeholder="Property"> <input type="text" id="v" placeholder="Value"> <button id="checkit">Check</button> </form> </body> </html>
The page presents two textfields in which the user can enter a CSS property and a value for that property. Clicking the "Check" button fires an event handler which includes the code CSS.supports(p, v)
; an alert indicates whether the current browser does or does not support the given property/value.
As of this writing, you can try property hyphens
and value manual
: the current version of Chrome does not support that property but the current version of Firefox does support it.