Scroll bar below fixed header with Vuetify + Electron - vuejs2

I am using Vuetify and Electron to make an app to help me with certain tasks at my job. I have disable the browserWindow frame and made my header the draggable area with a button to close the window. I am using the electron vuetify template
vue init vuetifyjs/electron
My problem is the scrollbar reaches all the way to the top but I would like it below my fixed header.
I have tried playing with overflow properties on the html, body, app div, and content div tags but i have not been successful.
How would I accomplish this?

This is purely a CSS question really as you can see this behaviour in the browser too with similar layouts. The easiest way to fix this is using a flex layout:
HTML:
<div class="container">
<div class="titlebar"></div>
<div class="content">
<h1>So much content we scroll</h1>
<h1>So much content we scroll</h1>
<!-- etc -->
</div>
</div>
CSS:
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.titlebar {
background-color: blue;
height: 35px;
flex-shrink: 0;
}
.content {
flex-grow: 1;
overflow-x: auto;
}
Check out this out in this CodePen

I'd like to offer a Vuetify specific answer for this question, this should apply whether or not Electron is involved.
Vuetify's default styles make this a bit more difficult than a simple CSS solution can give you, especially when the layout gets more complex.
For this example I'm using the complex layout from Vuetify's pre-defined themes here
Vuetify ships with an overflow-y: scroll on the html element so the first step is adding an override for this.
html {
overflow: hidden;
}
This will get rid of the bar on the right side that spans the whole height of the app.
Next you will want to set your v-content area as the scrollable area. There are a few gotchas to watch out for when you're setting this area:
Display flex is already declared
Vuetify sets padding in the style attribute so you'll need to override depending on your case
You'll need a margin the height of your header(only matters if you're changing header height from 64px)
You'll need to remove the header height from the height of the content container using calc(Same as above)
If you have a nav drawer on the right side you'll need to bind a class to take care of this.
My CSS for v-content looks like this, you will need an important to override the padding since it is set by Vuetify through style binding:
main.v-content {
width: 100vw;
height: calc(100vh - 64px);
flex-direction: column;
overflow: scroll;
margin-top: 64px;
padding-top: 0 !important;
}
I also have a class bound to the state of the temporary right drawer on the v-content tag in the template, this makes sure that the scroll bar doesn't disappear underneath the right nav drawer when it's open:
<v-content :class="{ draweropen: drawerRight }">
And the CSS for that bound class, once again you'll need an important to remove the default right padding Vuetify puts on v-content when the drawer is open:
.draweropen {
width: calc(100vw - 300px) !important;
padding-right: 0 !important;
}
You can optionally set the flex-direction to column-reverse if your content is bottom loaded like a chat which is what I'm doing in this CodePen Example

I built a little component that wraps the v-main and moves the scrollbar to the main container instead of the default (the entire html).
Simply replace v-main with this and you're done.
<template>
<v-main class="my-main">
<div class="my-main__scroll-container">
<slot />
</div>
</v-main>
</template>
<script>
export default {
mounted: function() {
let elHtml = document.getElementsByTagName('html')[0]
elHtml.style.overflowY = 'hidden'
},
destroyed: function() {
let elHtml = document.getElementsByTagName('html')[0]
elHtml.style.overflowY = null
},
}
</script>
<style>
.my-main
height: 100vh
.my-main__scroll-container
height: 100%
overflow: auto
</style>

Related

Customizing Swiper in Vue 3

I have a simple, functional swiper working in Vue 3 with Swiper.js 8.4.5 working off these Vue examples (sans scrollbar and A11y). As shown, everything appears to be working as intended.
<TileFormat>
<div style="width: 100%; height: 100%; display: flex">
<swiper
:modules="modules"
:slides-per-view="1"
:space-between="50"
navigation
:pagination="{ clickable: true }"
#swiper="onSwiper"
#slideChange="onSlideChange"
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper>
</div>
</TileFormat>
setup() {
const onSwiper = (swiper) => {
console.log(swiper);
};
const onSlideChange = () => {
console.log('slide change');
};
return {
onSwiper,
onSlideChange,
modules: [Navigation, Pagination, Scrollbar],
};
},
I would like to modify elements of the Navigation param (size, color, etc.) but have been unable to find a way to accomplish that. I have done this mostly with attempts to modify the css within the scoped style block of the view (which are ignored or overwritten). I've even tried skipping import 'swiper/css/navigation'; and rolling my own, but that doesn't work either. The examples of similar changes I can find seem to apply to versions of Swiper.js that aren't written for Vue 3.
The Swiper.js docs say:
Note, Swiper Vue.js component will create required elements for Navigation, Pagination and Scrollbar if you pass these params without specifying its elements (e.g. without navigation.nextEl, pagination.el, etc.)
I have come to the quasi-conclusion that I need to add my changes to the Navigation module within the setup() method before passing it; however, I can't seem to locate an example of how to do that.
What is the "most robust" way to modify Swiper components in Vue 3?
EDIT 1: By the way, this approach was also unsuccessful:
:navigation="{enabled: true, prevEl: '.myPrev', nextEl: '.myNext'}"
Usually, to be able to customize any kind of UI components (it being something like Bootstrap or a UI package), you use:
an increased specificity, hence why the ID is working in your case
an element as deep as you can, if you want to go further you can use :deep
the usage of !important may be overkill but that one is a good case to override such projects
Using an id instead of a class allowed me to customize the slider object (it still needs a lot of work). There may also be a specific class reference that will work, but the options I tried were ignored (or overwritten).
<TileFormat>
<div style="width: 100%; height: 100%; display: flex;">
<swiper
:modules="modules"
:slides-per-view="1"
:space-between="50"
navigation
:pagination="{ clickable: true }"
#swiper="onSwiper"
#slideChange="onSlideChange"
id="mySlider"
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper>
</div>
</TileFormat>
#mySlider .swiper-button-prev,
#mySlider .swiper-button-next {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 8px;
color: #888888;
--swiper-navigation-size: 20px;
}

How to pass css styles to plugins in Vue?

I use Vue-Editor.
<vue-editor id="editor" ref="editor" v-model="content" :use-custom-image-handler="true" #image-added ="added" #image-removed ="deleted" :key="componentKey"/>
On mobile devices, the icons are to small. I like to increase the icons size on mobile devices, but on medium devices, I like to keep the default size.
If I do it in this way, the size changes for all pages not only for the current page:
<style>
.p {
color: black
}
.ql-snow.ql-toolbar button {
height: 35px !important;
width: 35px !important;
}
.quillWrapper .ql-snow.ql-toolbar button svg {
width: 35px !important;
height: 35px !important;
}
</style>
If I do it with <style scoped> it doesn't pass the css to the plugin component.
How I can change the css for the plugin only in one Vue component without having a global effect?
You can keep scoped but then, you need to make a deep selector like >>> .ql-snow.ql-toolbar button to select the 3rd party library.
If using SASS, use ::v-deep, more details here.

Vue js: how to load a css animation only on the first page load

In the Home Page component, I've a <div> element with an animation, like this:
<div class="square">
//content
</div>
and in the CSS:
.square
height: 200px
width: 200px
margin: 0 auto
z-index: 0
position: absolute
top: 38vh
left: 43vw
margin-left:auto
margin-right:auto
animation-name: stretch
animation-duration: 0.3s
animation-timing-function: ease-out
animation-delay: 0
animation-direction: alternate
animation-fill-mode: forwards
animation-play-state: running
#keyframes stretch
from
transform: scale (1)
to
transform: scale(1.8)
It is a simple square that grows, with some other <div> elements inside.
Now, I would like to play the animation only on initial login and opening of app, not each time the view appears (like is working now).
Could you help me? Please, don't take anything for granted, because I am a beginner. Thank you in advance.
its simple. create a flag in the data of the vue property. you can call it animate. add a function that will turn it off after the login, somthing like:
data:{
animate:true
},
methods:{
turnOffAnimate:{
this.animate=false;
}
}
call this.turnOffAnimate when you want to turn off your animation. now, in your html div, bind the class in this way:
<div :class="{square : animate}">
//content
</div>
this condition means that your div will own square class only while animate flag is true. you can read more about class binding in vue.

MapBox (mapbox-gl-vue) renders the map on only 50% of the width of the container

I am trying MapBox with Vue 2 and I cannot make the map take the full width of the container. It only renders on 50% of the width of the container.
I have included the files in the head of my index.html as follows:
<script src='https://api.mapbox.com/mapbox-gl-js/v0.40.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v0.40.0/mapbox-gl.css' rel='stylesheet' />
I want the map in a component (Map.vue, I am using vue-router), so here is the code in Map.vue:
Script:
import Mapbox from 'mapbox-gl-vue';
export default {
components: {
'mapbox': Mapbox
}
}
Template:
<mapbox access-token="pk.eyJ1Ijoic3BlZW5pY3Q....."
:map-options="{
style: 'mapbox://styles/mapbox/streets-v9',
center: [-96, 37.8],
zoom: 3
}"
:geolocate-control="{
show: true,
position: 'top-left'
}"
:scale-control="{
show: true,
position: 'top-left'
}"
:fullscreen-control="{
show: true,
position: 'top-left'
}">>
</mapbox>
Style:
#map {
width: 100%;
height: 600px;
position: absolute;
margin:0;
z-index:1;
}
I have tried everything I know in the CSS id but it only renders the map in the right half of the width of the container, in the left one only the logo and the controls are displayed while the rest of the area is empty.
To solve the problem, I just had to delete "text-align: center;" from #app in App.vue.
For more details, check the issue I had opened here:
https://github.com/phegman/vue-mapbox-gl/issues/11
It looks like to me, there is something dynamic with the div or the div is rendered later after the instantiation. I have not used vue, however.
I have had this problem with tabs and div rendered after the page load such as in tabs or triggered by JavaScript.
If you use map.invalidateSize(); where map is the object instantiated. This will redraw the map. Try and put this after the window is loaded to test the code. Then perhaps it can be converted into the correct Vue implementation.
window.addEventListener("load", function(){
map.invalidateSize();
});;

How to create sticky header bar for a website

I want to create a sticky header bar for a website just like the sticky header on this website (http://www.fizzysoftware.com/) if any on can can help me out with coding or any resource that helps me to create the same. Your reply would be of great help to me.
In your CSS, add
position: fixed;
to your header element. It's just that simple, really.
And next time, try to use right click on something you see on website and choose "Inspect element". I think that every modern browser has it now. Very useful function.
If you want to make it sticky when it's scroll down to a certain point then you can use this function:
$window = $(window);
$window.scroll(function() {
$scroll_position = $window.scrollTop();
if ($scroll_position > 300) { // if body is scrolled down by 300 pixels
$('.your-header').addClass('sticky');
// to get rid of jerk
header_height = $('.your-header').innerHeight();
$('body').css('padding-top' , header_height);
} else {
$('body').css('padding-top' , '0');
$('.your-header').removeClass('sticky');
}
});
And sticky class:
.sticky {
position: fixed;
z-index: 9999;
width: 100%;
}
You can use this plugin and it has some useful options
jQuery Sticky Header
CSS already gives you the answer. Try this out
.sticky {
position: -webkit-sticky;
position: sticky;
top: 0;
}
now add the class sticky to any menu sidebar or anything you want to stick to the top and it will automatically calculate the margin and stick to the top. Cheers.
If you want simplicity in a HTML and CSS option to create a Stiky NavBar you can use the following:
Just create a navbar like this one:
<nav class="zone blue sticky">
<ul class="main-nav">
<li>About</li>
<li>Products</li>
<li>Our Team</li>
<li class="push">Contact</li>
</ul>
</nav>
Remember to add the classes in this case I created a Zone (to separate my HTML in specific areas I want my CSS to be applied) blue (just a color for the nav) and sticky which is the one that gonna carry our sticky function. You can work on other attributes you want to add is up to you.
On the CSS add the following to create the sticky; first I am gonna start with the zone tag
.zone {
/*padding:30px 50px;*/
cursor:pointer;
color:#FFF;
font-size:2em;
border-radius:4px;
border:1px solid #bbb;
transition: all 0.3s linear;
}
now with the sticky tag
.sticky {
position: fixed;
top: 0;
width: 100%;
}
Position fixed meaning it will always be in the same position; and with top 0 I will always be at the top and a 100% width so it covers the whole screen.
And now the color to make our navbar blue
.blue {
background: #7abcff;
You can use this example to create a sticky navbar of yours and play around with the CSS properties to customize it to your liking.
Try This
Add this style to the corresponding
style="position: fixed; width: -webkit-fill-available"
OR
<style>
.className{
position: fixed;
width: -webkit-fill-available;
}
</style>