Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js rendering issues with safari

I have a portfolio website written using Vue and Laravel that renders out project thumbnails with v-for. This works completely fine on every browser apart from on Safari, there's a weird issue where the images will not show up at all unless the user resizes the browser window. Heres the relevent code:

  <div class="project-list">
        <img v-show="!loaded" class="loading" src="../assets/contrast_load.gif" alt="loading...">
          <div class="project-container" v-for="project in shownProjects.slice().reverse()" v-bind:key="project.id">
            <figure class="project" @mouseover="gColor1 = project.color1; gColor2 = project.color2" @click="goToPage(project.id)" :style="`--overlay-color: ${project.color1};`">
              <img :src="`${base}/storage/app/${project.thumb_img}`" :alt="project.name" />
              <figcaption>
                <h3>{{ project.name }} <span v-bind:style="{color: project.color1}">{{ project.description }}</span></h3>
              </figcaption>
            </figure>
          </div>
      </div>
    </div>
  </div>
</template>

<script>
import LogoSVG from '../components/LogoSVG.vue';
import config from '../config';
import axios from 'axios';
export default {
  name: 'Portfolio',
  data(){
    return{
      search: '',
      projects: [],
      shownProjects: [],
      loaded: false,
      gColor1: '#752323',
      gColor2: '#e04747',
      base: config.BASE_URL,
    }
  },
  components:{
    LogoSVG,
  },
  watch:{
    search(){
      const vm = this;
      vm.shownProjects = [];
      if (vm.search == '') {
        vm.shownProjects = vm.projects;
      }
      else {
        for (var i = 0; i < vm.projects.length; i++) {
          if(vm.projects[i].tags.toLowerCase().search(vm.search.toLowerCase()) > -1){
            vm.shownProjects.push(vm.projects[i]);
          }
        }
      }
    },
  },
  methods:{
  getProjects(){
    const vm = this;
    vm.loaded = false;
    axios.get(`${config.APP_URL}/api/projects`)
    .then(function (response) {
        vm.projects = response.data;
        vm.shownProjects = response.data;
        window.onload = function() {
          vm.loaded = true;
        };
      });
    },
    goToPage(r){
      this.$router.push('project/' + r);
    },
  }
}
</script>

<style scoped>
  .loading{
    position: absolute;
    width: 50px;
    height: 50px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }


  .project-list{
    width: 90%;
    height: 70%;
    position: absolute;
    display: flex;
    display: -webkit-flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    left: 50%;
    top: 65%;
    transform: translate(-50%, -50%);
    align-content: flex-start;
    overflow-y: scroll;
    overflow-x: hidden;
  }

  .project-container{
    width: 33%;
    height: 30vh;
  }

  .project {
    background-color: #2A2A2A;
    color: #FFF;
    font-family: 'Roboto', sans-serif;
    font-size: 18px;
    margin: 8px;
    max-width: 100%;
    min-width: 230px;
    overflow: hidden;
    position: relative;
    text-align: center;
    width: 100%;
    height: 100%;
    cursor: pointer;
  }

  .project * {
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    -webkit-transition: all 0.45s ease;
    transition: all 0.45s ease;
    cursor: pointer;
  }

  .project:after {
    background-color: var(--overlay-color);
    height: 150%;
    bottom: -145%;
    content: '';
    left: 0;
    right: 0;
    position: absolute;
    -webkit-transition: all 0.2s linear;
    transition: all 0.4s linear;
    cursor: pointer;
  }

  .project img {
    vertical-align: top;
    backface-visibility: hidden;
    max-height: 100%;
    object-fit: cover;
  }

  .project figcaption {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 10%;
    right: 10%;
    align-items: center;
    z-index: 1;
    display: flex;
    width: 80%;
    flex-direction: column;
    justify-content: center;
    line-height: 1.1em;
    opacity: 0;
    -webkit-transition-delay: 0s;
    transition-delay: 0s;
  }

  .project h3 {
    font-size: 1em;
    font-weight: 400;
    letter-spacing: 1px;
    margin: 0;
    text-transform: uppercase;
  }

  .project h3 span {
    display: block;
    font-weight: 700;
  }

  .project a {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1;
  }

  .project:hover > img,
  .project.hover > img {
    opacity: 0.1;
  }

  .project:hover:after,
  .project.hover:after {
    bottom: 95%;
  }

  .project:hover figcaption,
  .project.hover figcaption {
    opacity: 1;
    -webkit-transition-delay: 0.3s;
    transition-delay: 0.3s;
  }

  .project-fade-leave-active,
  .project-fade-enter-active {
    transition: 0.4s all;
  }
  .project-fade-enter,
  .project-fade-leave-to  {
    opacity: 0;
  }

  @-webkit-keyframes fadeDown {
    0%   {
      top: 4vh;
      opacity: 0;
    }
    100%{
      top: 5vh;
      opacity: 1;
    }
  }

  @-webkit-keyframes fade {
    0%   {
      opacity: 0;
    }
    100%{
      opacity: 1;
    }
  }
</style>

and you can visit the page here: https://www.redsquirrelstudio.co.uk/#/portfolio

Any help would be greatly appreciated this has been a real headache.

like image 356
RedSquirrel Studio Avatar asked Aug 31 '25 22:08

RedSquirrel Studio


2 Answers

Found out the issue. Apparently safari isn't the best with reacting to changes in data in Vue. I added an element in that changes when the rest of the data loads which triggers everything else to update.

Very strange.

like image 90
RedSquirrel Studio Avatar answered Sep 03 '25 14:09

RedSquirrel Studio


Just in case anyone finds this question in the future (like me) I would like to point out a few things that made Safari render the correct data from the state:

  • Use a v-bind directive in any element that fails to update. In my case, my div ended up like <div :key="targetObject.guid">.

  • Use dummy CSS properties for elements that also need to be updated. The ones I used were the following:

.problematic-element {
   display: inline-block;
   min-width: 0%;
   transform: translateZ(0);
}
like image 24
lagunatenofelix Avatar answered Sep 03 '25 14:09

lagunatenofelix