main
1/*
2 * noVNC base CSS
3 * Copyright (C) 2019 The noVNC authors
4 * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
5 * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
6 */
7
8/*
9 * Z index layers:
10 *
11 * 0: Main screen
12 * 10: Control bar
13 * 50: Transition blocker
14 * 60: Connection popups
15 * 100: Status bar
16 * ...
17 * 1000: Javascript crash
18 * ...
19 * 10000: Max (used for polyfills)
20 */
21
22/*
23 * State variables (set on :root):
24 *
25 * noVNC_loading: Page is still loading
26 * noVNC_connecting: Connecting to server
27 * noVNC_reconnecting: Re-establishing a connection
28 * noVNC_connected: Connected to server (most common state)
29 * noVNC_disconnecting: Disconnecting from server
30 */
31
32:root {
33 font-family: sans-serif;
34 line-height: 1.6;
35}
36
37body {
38 margin:0;
39 padding:0;
40 /*Background image with light grey curve.*/
41 background-color:#494949;
42 background-repeat:no-repeat;
43 background-position:right bottom;
44 height:100%;
45 touch-action: none;
46}
47
48html {
49 height:100%;
50}
51
52.noVNC_only_touch.noVNC_hidden {
53 display: none;
54}
55
56.noVNC_disabled {
57 color: var(--novnc-grey);
58}
59
60/* ----------------------------------------
61 * Spinner
62 * ----------------------------------------
63 */
64
65.noVNC_spinner {
66 position: relative;
67}
68.noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after {
69 width: 10px;
70 height: 10px;
71 border-radius: 2px;
72 box-shadow: -60px 10px 0 rgba(255, 255, 255, 0);
73 animation: noVNC_spinner 1.0s linear infinite;
74}
75.noVNC_spinner::before {
76 content: "";
77 position: absolute;
78 left: 0px;
79 top: 0px;
80 animation-delay: -0.1s;
81}
82.noVNC_spinner::after {
83 content: "";
84 position: absolute;
85 top: 0px;
86 left: 0px;
87 animation-delay: 0.1s;
88}
89@keyframes noVNC_spinner {
90 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; }
91 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; }
92 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; }
93}
94
95/* ----------------------------------------
96 * WebKit centering hacks
97 * ----------------------------------------
98 */
99
100.noVNC_center {
101 /*
102 * This is a workaround because webkit misrenders transforms and
103 * uses non-integer coordinates, resulting in blurry content.
104 * Ideally we'd use "top: 50%; transform: translateY(-50%);" on
105 * the objects instead.
106 */
107 display: flex;
108 align-items: center;
109 justify-content: center;
110 position: fixed;
111 top: 0;
112 left: 0;
113 width: 100%;
114 height: 100%;
115 pointer-events: none;
116}
117.noVNC_center > * {
118 pointer-events: auto;
119}
120.noVNC_vcenter {
121 display: flex !important;
122 flex-direction: column;
123 justify-content: center;
124 position: fixed;
125 top: 0;
126 left: 0;
127 height: 100%;
128 margin: 0 !important;
129 padding: 0 !important;
130 pointer-events: none;
131}
132.noVNC_vcenter > * {
133 pointer-events: auto;
134}
135
136/* ----------------------------------------
137 * Layering
138 * ----------------------------------------
139 */
140
141.noVNC_connect_layer {
142 z-index: 60;
143}
144
145/* ----------------------------------------
146 * Fallback error
147 * ----------------------------------------
148 */
149
150#noVNC_fallback_error {
151 z-index: 1000;
152 visibility: hidden;
153 /* Put a dark background in front of everything but the error,
154 and don't let mouse events pass through */
155 background: rgba(0, 0, 0, 0.8);
156 pointer-events: all;
157}
158#noVNC_fallback_error.noVNC_open {
159 visibility: visible;
160}
161
162#noVNC_fallback_error > div {
163 max-width: calc(100vw - 30px - 30px);
164 max-height: calc(100vh - 30px - 30px);
165 overflow: auto;
166
167 padding: 15px;
168
169 transition: 0.5s ease-in-out;
170
171 transform: translateY(-50px);
172 opacity: 0;
173
174 text-align: center;
175 font-weight: bold;
176 color: #fff;
177
178 border-radius: 12px;
179 box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
180 background: rgba(200,55,55,0.8);
181}
182#noVNC_fallback_error.noVNC_open > div {
183 transform: translateY(0);
184 opacity: 1;
185}
186
187#noVNC_fallback_errormsg {
188 font-weight: normal;
189}
190
191#noVNC_fallback_errormsg .noVNC_message {
192 display: inline-block;
193 text-align: left;
194 font-family: monospace;
195 white-space: pre-wrap;
196}
197
198#noVNC_fallback_error .noVNC_location {
199 font-style: italic;
200 font-size: 0.8em;
201 color: rgba(255, 255, 255, 0.8);
202}
203
204#noVNC_fallback_error .noVNC_stack {
205 padding: 10px;
206 margin: 10px;
207 font-size: 0.8em;
208 text-align: left;
209 font-family: monospace;
210 white-space: pre;
211 border: 1px solid rgba(0, 0, 0, 0.5);
212 background: rgba(0, 0, 0, 0.2);
213 overflow: auto;
214}
215
216/* ----------------------------------------
217 * Control bar
218 * ----------------------------------------
219 */
220
221#noVNC_control_bar_anchor {
222 /* The anchor is needed to get z-stacking to work */
223 position: fixed;
224 z-index: 10;
225
226 transition: 0.5s ease-in-out;
227
228 /* Edge misrenders animations wihthout this */
229 transform: translateX(0);
230}
231:root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle {
232 opacity: 0.8;
233}
234#noVNC_control_bar_anchor.noVNC_right {
235 left: auto;
236 right: 0;
237}
238
239#noVNC_control_bar {
240 position: relative;
241 left: -100%;
242
243 transition: 0.5s ease-in-out;
244
245 background-color: var(--novnc-blue);
246 border-radius: 0 12px 12px 0;
247
248 user-select: none;
249 -webkit-user-select: none;
250 -webkit-touch-callout: none; /* Disable iOS image long-press popup */
251}
252#noVNC_control_bar.noVNC_open {
253 box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
254 left: 0;
255}
256#noVNC_control_bar::before {
257 /* This extra element is to get a proper shadow */
258 content: "";
259 position: absolute;
260 z-index: -1;
261 height: 100%;
262 width: 30px;
263 left: -30px;
264 transition: box-shadow 0.5s ease-in-out;
265}
266#noVNC_control_bar.noVNC_open::before {
267 box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
268}
269.noVNC_right #noVNC_control_bar {
270 left: 100%;
271 border-radius: 12px 0 0 12px;
272}
273.noVNC_right #noVNC_control_bar.noVNC_open {
274 left: 0;
275}
276.noVNC_right #noVNC_control_bar::before {
277 visibility: hidden;
278}
279
280#noVNC_control_bar_handle {
281 position: absolute;
282 left: -15px;
283 top: 0;
284 transform: translateY(35px);
285 width: calc(100% + 30px);
286 height: 50px;
287 z-index: -1;
288 cursor: pointer;
289 border-radius: 6px;
290 background-color: var(--novnc-darkblue);
291 background-image: url("../images/handle_bg.svg");
292 background-repeat: no-repeat;
293 background-position: right;
294 box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5);
295}
296#noVNC_control_bar_handle:after {
297 content: "";
298 transition: transform 0.5s ease-in-out;
299 background: url("../images/handle.svg");
300 position: absolute;
301 top: 22px; /* (50px-6px)/2 */
302 right: 5px;
303 width: 5px;
304 height: 6px;
305}
306#noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
307 transform: translateX(1px) rotate(180deg);
308}
309:root:not(.noVNC_connected) #noVNC_control_bar_handle {
310 display: none;
311}
312.noVNC_right #noVNC_control_bar_handle {
313 background-position: left;
314}
315.noVNC_right #noVNC_control_bar_handle:after {
316 left: 5px;
317 right: 0;
318 transform: translateX(1px) rotate(180deg);
319}
320.noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
321 transform: none;
322}
323/* Larger touch area for the handle, used when a touch screen is available */
324#noVNC_control_bar_handle div {
325 position: absolute;
326 right: -35px;
327 top: 0;
328 width: 50px;
329 height: 100%;
330 display: none;
331}
332@media (any-pointer: coarse) {
333 #noVNC_control_bar_handle div {
334 display: initial;
335 }
336}
337.noVNC_right #noVNC_control_bar_handle div {
338 left: -35px;
339 right: auto;
340}
341
342#noVNC_control_bar > .noVNC_scroll {
343 max-height: 100vh; /* Chrome is buggy with 100% */
344 overflow-x: hidden;
345 overflow-y: auto;
346 padding: 0 10px;
347}
348
349#noVNC_control_bar > .noVNC_scroll > * {
350 display: block;
351 margin: 10px auto;
352}
353
354/* Control bar hint */
355#noVNC_hint_anchor {
356 position: fixed;
357 right: -50px;
358 left: auto;
359}
360#noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor {
361 left: -50px;
362 right: auto;
363}
364#noVNC_control_bar_hint {
365 position: relative;
366 transform: scale(0);
367 width: 100px;
368 height: 50%;
369 max-height: 600px;
370
371 visibility: hidden;
372 opacity: 0;
373 transition: 0.2s ease-in-out;
374 background: transparent;
375 box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue);
376 border-radius: 12px;
377 transition-delay: 0s;
378}
379#noVNC_control_bar_hint.noVNC_active {
380 visibility: visible;
381 opacity: 1;
382 transition-delay: 0.2s;
383 transform: scale(1);
384}
385#noVNC_control_bar_hint.noVNC_notransition {
386 transition: none !important;
387}
388
389/* Control bar buttons */
390#noVNC_control_bar .noVNC_button {
391 min-width: unset;
392 padding: 4px 4px;
393 vertical-align: middle;
394 border:1px solid rgba(255, 255, 255, 0.2);
395 border-radius: 6px;
396 background-color: transparent;
397}
398#noVNC_control_bar .noVNC_button.noVNC_selected {
399 border-color: rgba(0, 0, 0, 0.8);
400 background-color: rgba(0, 0, 0, 0.5);
401}
402#noVNC_control_bar .noVNC_button.noVNC_hidden {
403 display: none !important;
404}
405
406/* Panels */
407.noVNC_panel {
408 transform: translateX(25px);
409
410 transition: 0.5s ease-in-out;
411
412 box-sizing: border-box; /* so max-width don't have to care about padding */
413 max-width: calc(100vw - 75px - 25px); /* minus left and right margins */
414 max-height: 100vh; /* Chrome is buggy with 100% */
415 overflow-x: hidden;
416 overflow-y: auto;
417
418 visibility: hidden;
419 opacity: 0;
420
421 padding: 15px;
422
423 background: #fff;
424 border-radius: 12px;
425 color: #000;
426 border: 2px solid #E0E0E0;
427 box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
428}
429.noVNC_panel.noVNC_open {
430 visibility: visible;
431 opacity: 1;
432 transform: translateX(75px);
433}
434.noVNC_right .noVNC_vcenter {
435 left: auto;
436 right: 0;
437}
438.noVNC_right .noVNC_panel {
439 transform: translateX(-25px);
440}
441.noVNC_right .noVNC_panel.noVNC_open {
442 transform: translateX(-75px);
443}
444
445.noVNC_panel > * {
446 display: block;
447 margin: 10px auto;
448}
449.noVNC_panel > *:first-child {
450 margin-top: 0 !important;
451}
452.noVNC_panel > *:last-child {
453 margin-bottom: 0 !important;
454}
455
456.noVNC_panel hr {
457 border: none;
458 border-top: 1px solid var(--novnc-lightgrey);
459 width: 100%; /* <hr> inside a flexbox will otherwise be 0px wide */
460}
461
462.noVNC_panel label {
463 display: block;
464 white-space: nowrap;
465 margin: 5px;
466}
467@media (max-width: 540px) {
468 /* Allow wrapping on small screens */
469 .noVNC_panel label {
470 white-space: unset;
471 }
472}
473
474.noVNC_panel li {
475 margin: 5px;
476}
477
478.noVNC_panel .noVNC_heading {
479 background-color: var(--novnc-blue);
480 border-radius: 6px;
481 padding: 5px 8px;
482 /* Compensate for padding in image */
483 padding-right: 11px;
484 display: flex;
485 align-items: center;
486 gap: 6px;
487 color: white;
488 font-size: 20px;
489 font-weight: bold;
490 white-space: nowrap;
491}
492.noVNC_panel .noVNC_heading img {
493 vertical-align: bottom;
494}
495
496.noVNC_panel form {
497 display: flex;
498 flex-direction: column;
499 gap: 12px
500}
501
502.noVNC_panel .button_row {
503 margin-top: 10px;
504 display: flex;
505 gap: 10px;
506 justify-content: space-between;
507}
508.noVNC_panel .button_row *:only-child {
509 margin-left: auto; /* Align single buttons to the right */
510}
511
512/* Expanders */
513.noVNC_expander {
514 cursor: pointer;
515}
516.noVNC_expander::before {
517 content: url("../images/expander.svg");
518 display: inline-block;
519 margin-right: 5px;
520 transition: 0.2s ease-in-out;
521}
522.noVNC_expander.noVNC_open::before {
523 transform: rotateZ(90deg);
524}
525.noVNC_expander ~ * {
526 margin: 5px;
527 margin-left: 10px;
528 padding: 5px;
529 background: rgba(0, 0, 0, 0.04);
530 border-radius: 6px;
531}
532.noVNC_expander:not(.noVNC_open) ~ * {
533 display: none;
534}
535
536/* Control bar content */
537
538#noVNC_control_bar .noVNC_logo {
539 font-size: 13px;
540}
541
542.noVNC_logo + hr {
543 /* Remove all but top border */
544 border: none;
545 border-top: 1px solid rgba(255, 255, 255, 0.2);
546}
547
548:root:not(.noVNC_connected) #noVNC_view_drag_button {
549 display: none;
550}
551
552/* noVNC Touch Device only buttons */
553:root:not(.noVNC_connected) #noVNC_mobile_buttons {
554 display: none;
555}
556@media not all and (any-pointer: coarse) {
557 /* FIXME: The button for the virtual keyboard is the only button in this
558 group of "mobile buttons". It is bad to assume that no touch
559 devices have physical keyboards available. Hopefully we can get
560 a media query for this:
561 https://github.com/w3c/csswg-drafts/issues/3871 */
562 :root.noVNC_connected #noVNC_mobile_buttons {
563 display: none;
564 }
565}
566
567/* Extra manual keys */
568:root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button {
569 display: none;
570}
571
572#noVNC_modifiers {
573 background-color: var(--novnc-darkgrey);
574 border: none;
575 padding: 10px;
576}
577
578/* Shutdown/Reboot */
579:root:not(.noVNC_connected) #noVNC_power_button {
580 display: none;
581}
582#noVNC_power {
583}
584#noVNC_power_buttons {
585 display: none;
586}
587
588#noVNC_power input[type=button] {
589 width: 100%;
590}
591
592/* Clipboard */
593:root:not(.noVNC_connected) #noVNC_clipboard_button {
594 display: none;
595}
596#noVNC_clipboard_text {
597 width: 360px;
598 min-width: 150px;
599 height: 160px;
600 min-height: 70px;
601
602 box-sizing: border-box;
603 max-width: 100%;
604 /* minus approximate height of title, height of subtitle, and margin */
605 max-height: calc(100vh - 10em - 25px);
606}
607
608/* Settings */
609#noVNC_settings {
610}
611#noVNC_settings ul {
612 list-style: none;
613 padding: 0px;
614}
615#noVNC_settings button,
616#noVNC_settings select,
617#noVNC_settings textarea,
618#noVNC_settings input:not([type=checkbox]):not([type=radio]) {
619 margin-left: 6px;
620 /* Prevent inputs in settings from being too wide */
621 max-width: calc(100% - 6px - var(--input-xpadding) * 2);
622}
623
624#noVNC_setting_port {
625 width: 80px;
626}
627#noVNC_setting_path {
628 width: 100px;
629}
630
631/* Version */
632
633.noVNC_version_wrapper {
634 font-size: small;
635}
636
637.noVNC_version {
638 margin-left: 1rem;
639}
640
641/* Connection controls */
642:root:not(.noVNC_connected) #noVNC_disconnect_button {
643 display: none;
644}
645
646/* ----------------------------------------
647 * Status dialog
648 * ----------------------------------------
649 */
650
651#noVNC_status {
652 position: fixed;
653 top: 0;
654 left: 0;
655 width: 100%;
656 z-index: 100;
657 transform: translateY(-100%);
658
659 cursor: pointer;
660
661 transition: 0.5s ease-in-out;
662
663 visibility: hidden;
664 opacity: 0;
665
666 padding: 5px;
667
668 display: flex;
669 flex-direction: row;
670 justify-content: center;
671 align-content: center;
672
673 line-height: 1.6;
674 word-wrap: break-word;
675 color: #fff;
676
677 border-bottom: 1px solid rgba(0, 0, 0, 0.9);
678}
679#noVNC_status.noVNC_open {
680 transform: translateY(0);
681 visibility: visible;
682 opacity: 1;
683}
684
685#noVNC_status::before {
686 content: "";
687 display: inline-block;
688 width: 25px;
689 height: 25px;
690 margin-right: 5px;
691}
692
693#noVNC_status.noVNC_status_normal {
694 background: rgba(128,128,128,0.9);
695}
696#noVNC_status.noVNC_status_normal::before {
697 content: url("../images/info.svg") " ";
698}
699#noVNC_status.noVNC_status_error {
700 background: rgba(200,55,55,0.9);
701}
702#noVNC_status.noVNC_status_error::before {
703 content: url("../images/error.svg") " ";
704}
705#noVNC_status.noVNC_status_warn {
706 background: rgba(180,180,30,0.9);
707}
708#noVNC_status.noVNC_status_warn::before {
709 content: url("../images/warning.svg") " ";
710}
711
712/* ----------------------------------------
713 * Connect dialog
714 * ----------------------------------------
715 */
716
717#noVNC_connect_dlg {
718 transition: 0.5s ease-in-out;
719
720 transform: scale(0, 0);
721 visibility: hidden;
722 opacity: 0;
723}
724#noVNC_connect_dlg.noVNC_open {
725 transform: scale(1, 1);
726 visibility: visible;
727 opacity: 1;
728}
729#noVNC_connect_dlg .noVNC_logo {
730 transition: 0.5s ease-in-out;
731 padding: 10px;
732 margin-bottom: 10px;
733
734 font-size: 80px;
735 text-align: center;
736
737 border-radius: 6px;
738}
739@media (max-width: 440px) {
740 #noVNC_connect_dlg {
741 max-width: calc(100vw - 100px);
742 }
743 #noVNC_connect_dlg .noVNC_logo {
744 font-size: calc(25vw - 30px);
745 }
746}
747#noVNC_connect_dlg div {
748 padding: 18px;
749
750 background-color: var(--novnc-darkgrey);
751 border-radius: 12px;
752 text-align: center;
753 font-size: 20px;
754
755 box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
756}
757#noVNC_connect_button {
758 width: 100%;
759 padding: 6px 30px;
760 cursor: pointer;
761 border-color: transparent;
762 border-radius: 12px;
763 background-color: var(--novnc-blue);
764 color: white;
765
766 display: flex;
767 justify-content: center;
768 place-items: center;
769 gap: 4px;
770}
771
772#noVNC_connect_button img {
773 vertical-align: bottom;
774 height: 1.3em;
775}
776
777/* ----------------------------------------
778 * Server verification dialog
779 * ----------------------------------------
780 */
781
782#noVNC_verify_server_dlg {
783 position: relative;
784
785 transform: translateY(-50px);
786}
787#noVNC_verify_server_dlg.noVNC_open {
788 transform: translateY(0);
789}
790#noVNC_fingerprint_block {
791 margin: 10px;
792}
793
794/* ----------------------------------------
795 * Password dialog
796 * ----------------------------------------
797 */
798
799#noVNC_credentials_dlg {
800 position: relative;
801
802 transform: translateY(-50px);
803}
804#noVNC_credentials_dlg.noVNC_open {
805 transform: translateY(0);
806}
807#noVNC_username_block.noVNC_hidden,
808#noVNC_password_block.noVNC_hidden {
809 display: none;
810}
811
812
813/* ----------------------------------------
814 * Main area
815 * ----------------------------------------
816 */
817
818/* Transition screen */
819#noVNC_transition {
820 transition: 0.5s ease-in-out;
821
822 display: flex;
823 opacity: 0;
824 visibility: hidden;
825
826 position: fixed;
827 top: 0;
828 left: 0;
829 bottom: 0;
830 right: 0;
831
832 color: white;
833 background: rgba(0, 0, 0, 0.5);
834 z-index: 50;
835
836 /*display: flex;*/
837 align-items: center;
838 justify-content: center;
839 flex-direction: column;
840}
841:root.noVNC_loading #noVNC_transition,
842:root.noVNC_connecting #noVNC_transition,
843:root.noVNC_disconnecting #noVNC_transition,
844:root.noVNC_reconnecting #noVNC_transition {
845 opacity: 1;
846 visibility: visible;
847}
848:root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button {
849 display: none;
850}
851#noVNC_transition_text {
852 font-size: 1.5em;
853}
854
855/* Main container */
856#noVNC_container {
857 width: 100%;
858 height: 100%;
859 background-color: #313131;
860 border-bottom-right-radius: 800px 600px;
861 /*border-top-left-radius: 800px 600px;*/
862
863 /* If selection isn't disabled, long-pressing stuff in the sidebar
864 can accidentally select the container or the canvas. This can
865 happen when attempting to move the handle. */
866 user-select: none;
867 -webkit-user-select: none;
868}
869
870#noVNC_keyboardinput {
871 width: 1px;
872 height: 1px;
873 background-color: #fff;
874 color: #fff;
875 border: 0;
876 position: absolute;
877 left: -40px;
878 z-index: -1;
879 ime-mode: disabled;
880}
881
882/*Default noVNC logo.*/
883/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
884@font-face {
885 font-family: 'Orbitron';
886 font-style: normal;
887 font-weight: 700;
888 src: local('?'), url('Orbitron700.woff') format('woff'),
889 url('Orbitron700.ttf') format('truetype');
890}
891
892.noVNC_logo {
893 color: var(--novnc-yellow);
894 font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
895 line-height: 0.9;
896 text-shadow: 0.1em 0.1em 0 black;
897}
898.noVNC_logo span{
899 color: var(--novnc-green);
900}
901
902#noVNC_bell {
903 display: none;
904}
905
906/* ----------------------------------------
907 * Media sizing
908 * ----------------------------------------
909 */
910
911@media screen and (max-width: 640px){
912 #noVNC_logo {
913 font-size: 150px;
914 }
915}
916
917@media screen and (min-width: 321px) and (max-width: 480px) {
918 #noVNC_logo {
919 font-size: 110px;
920 }
921}
922
923@media screen and (max-width: 320px) {
924 #noVNC_logo {
925 font-size: 90px;
926 }
927}